Add more stuff

This commit is contained in:
luis
2026-09-24 10:45:30 -03:00
parent 33dffdf87b
commit fdb2c9392a
11 changed files with 356 additions and 25 deletions
@@ -0,0 +1,38 @@
/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ResourcesService.h"
#include "BattlenetRpcErrorCodes.h"
#include "Session.h"
namespace Battlenet::Services
{
ResourcesService::ResourcesService(Session* session) : ResourcesBaseService(session)
{
}
uint32 ResourcesService::HandleGetContentHandle(resources::v1::ContentHandleRequest const*, ::bgs::protocol::ContentHandle* response, std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)>& /*continuation*/)
{
static constexpr char const* ShopContentHash = "\x57\x22\x12\xEC\x79\x41\x60\x53\x0C\xD5\x2E\xC4\x6E\x0D\xF2\x38\x03\x75\x7D\xCF\xF3\xAF\xF7\x95\x56\xBF\x85\x1A\xDC\x62\x5A\xAC";
response->set_region(0x5553); // "US"
response->set_usage(0x70667479); // "pfty"
response->set_hash(ShopContentHash, 32);
response->set_proto_url("https://prod.depot.battle.net/${hash}.${usage}");
return ERROR_OK;
}
}
@@ -0,0 +1,37 @@
/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TRINITYCORE_RESOURCES_SERVICE_H
#define TRINITYCORE_RESOURCES_SERVICE_H
#include "Service.h"
#include "Client/resource_service.pb.h"
namespace Battlenet::Services
{
class ResourcesService : public Service<resources::v1::ResourcesService>
{
typedef Service<resources::v1::ResourcesService> ResourcesBaseService;
public:
ResourcesService(Session* session);
uint32 HandleGetContentHandle(resources::v1::ContentHandleRequest const* request, ::bgs::protocol::ContentHandle* response, std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)>& continuation) override;
};
}
#endif // TRINITYCORE_RESOURCES_SERVICE_H
@@ -21,6 +21,7 @@
#include "ConnectionService.h"
#include "GameUtilitiesService.h"
#include "Log.h"
#include "ResourcesService.h"
#include "Session.h"
#include "Client/api/client/v1/block_list_listener.pb.h"
#include "Client/api/client/v1/block_list_service.pb.h"
@@ -59,7 +60,7 @@ Battlenet::ServiceDispatcher::ServiceDispatcher()
AddService<Service<report::v1::ReportService>>();
AddService<Service<report::v2::ReportService>>();
AddService<Service<report::v3::client::ReportService>>();
AddService<Service<resources::v1::ResourcesService>>();
AddService<Services::ResourcesService>();
AddService<Service<whisper::v2::client::WhisperService>>();
}
+56 -18
View File
@@ -706,6 +706,9 @@ void WorldSession::HandleCharEnum(CharacterDatabaseQueryHolder const& holder)
});
}
if (_warbandGroups)
charEnum.WarbandGroups = _warbandGroups->Groups;
SendPacket(charEnum.Write());
if (!charEnum.IsDeletedCharacters)
@@ -3369,28 +3372,63 @@ void WorldSession::SendUndeleteCharacterResponse(CharacterUndeleteResult result,
}
//WowCommunity
void WorldSession::HandleGetAccountCharListOpcode(WorldPackets::Character::GetAccountCharacterList& /*accountCharList*/)
void WorldSession::HandleSetupWarbandGroups(WorldPackets::Character::SetupWarbandGroups& setupWarbandGroups)
{
////TODOFROST - real result, tidy and confirm safe! currently this doesnt work for multiple realms!
//auto handler = [this, token = accountCharList.Token](EnumCharactersQueryHolder const& holder) {
if (!_warbandGroups)
_warbandGroups = std::make_unique<WorldPackets::Character::AccountWarbandGroups>();
// WorldPackets::Character::GetAccountCharacterListResult list_result;
// list_result.Token = token;
_warbandGroups->Groups = std::move(setupWarbandGroups.Groups);
}
// if (PreparedQueryResult result = holder.GetPreparedResult(EnumCharactersQueryHolder::CHARACTERS))
// {
// do {
// WorldPackets::Character::GetAccountCharacterListResult::CharacterListEntry temp{ result->Fetch() };
// temp.AccountGuid = GetAccountGUID();
// temp.lastLoginUnixSec = 0; //TODOFROST
// temp.RealmName = realm.Name;
// temp.RealmVirtualAddress = GetVirtualRealmAddress();
// list_result.Characters.push_back(temp);
// } while (result->NextRow() && list_result.Characters.size() < MAX_CHARACTERS_PER_REALM);
// }
void WorldSession::HandleGetAccountCharListOpcode(WorldPackets::Character::GetAccountCharacterList& accountCharList)
{
uint32 const token = accountCharList.Token;
// SendPacket(list_result.Write());
// };
auto sendEmpty = [this, token]()
{
WorldPackets::Character::GetAccountCharacterListResult empty;
empty.Token = token;
SendPacket(empty.Write());
};
std::shared_ptr<EnumCharactersQueryHolder> holder = std::make_shared<EnumCharactersQueryHolder>();
if (!holder->Initialize(GetAccountId(), false, false))
{
sendEmpty();
return;
}
AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(holder)).AfterComplete([this, token](SQLQueryHolderBase const& result)
{
WorldPackets::Character::GetAccountCharacterListResult list;
list.Token = token;
std::string realmName;
if (std::shared_ptr<Realm const> currentRealm = sRealmList->GetCurrentRealm())
realmName = currentRealm->Name;
EnumCharactersQueryHolder const& holderResult = static_cast<EnumCharactersQueryHolder const&>(result);
if (PreparedQueryResult characters = holderResult.GetPreparedResult(EnumCharactersQueryHolder::CHARACTERS))
{
do
{
Field const* fields = characters->Fetch();
WorldPackets::Character::GetAccountCharacterListResult::CharacterInfo& entry = list.Characters.emplace_back();
entry.WowAccount = GetAccountGUID();
entry.Guid = ObjectGuid::Create<HighGuid::Player>(fields[0].GetUInt64());
entry.VirtualRealmAddress = GetVirtualRealmAddress();
entry.RaceID = fields[2].GetUInt8();
entry.ClassID = fields[3].GetUInt8();
entry.SexID = fields[4].GetUInt8();
entry.ExperienceLevel = fields[5].GetUInt8();
entry.LastActiveTime = uint64(fields[20].GetInt64());
entry.Name = fields[1].GetString();
entry.RealmName = realmName;
} while (characters->NextRow() && list.Characters.size() < MAX_CHARACTERS_PER_REALM);
}
SendPacket(list.Write());
});
}
void WorldSession::HandleGetRafAccountInfo(WorldPackets::RaF::GetRafAccountInfo& packet)
@@ -948,4 +948,82 @@ namespace WorldPackets::Character
_worldPacket << uint32(0);
return &_worldPacket;
}
void GetAccountCharacterList::Read()
{
_worldPacket >> Token;
_worldPacket.rfinish();
}
WorldPacket const* GetAccountCharacterListResult::Write()
{
_worldPacket << uint32(Token);
_worldPacket << uint32(Characters.size());
for (CharacterInfo const& character : Characters)
{
_worldPacket << character.WowAccount;
_worldPacket << character.Guid;
_worldPacket << uint32(character.VirtualRealmAddress);
_worldPacket << uint8(character.RaceID);
_worldPacket << uint8(character.ClassID);
_worldPacket << uint8(character.SexID);
_worldPacket << uint8(character.ExperienceLevel);
_worldPacket << uint64(character.LastActiveTime);
_worldPacket << int32(character.ContentSetID);
_worldPacket << SizedString::BitsSize<6>(character.Name);
_worldPacket << SizedString::BitsSize<9>(character.RealmName);
_worldPacket.FlushBits();
_worldPacket << SizedString::Data(character.Name);
_worldPacket << SizedString::Data(character.RealmName);
}
_worldPacket << Bits<1>(ConsoleCommand);
_worldPacket.FlushBits();
return &_worldPacket;
}
void SetupWarbandGroups::Read()
{
uint32 groupCount = 0;
_worldPacket >> Bits<5>(groupCount);
if (groupCount > 31)
{
_worldPacket.rfinish();
return;
}
Groups.resize(groupCount);
for (WarbandGroup& group : Groups)
{
_worldPacket >> group.GroupID;
_worldPacket >> group.OrderIndex;
_worldPacket >> group.WarbandSceneID;
_worldPacket >> group.Flags;
_worldPacket >> group.ContentSetID;
uint32 memberCount = 0;
_worldPacket >> memberCount;
if (memberCount > 50)
{
Groups.clear();
_worldPacket.rfinish();
return;
}
group.Members.resize(memberCount);
for (WarbandGroupMember& member : group.Members)
{
_worldPacket >> member.WarbandScenePlacementID;
_worldPacket >> member.Type;
_worldPacket >> member.ContentSetID;
if (member.Type == 0)
_worldPacket >> member.Guid;
}
_worldPacket >> SizedString::BitsSize<9>(group.Name);
_worldPacket >> SizedString::Data(group.Name);
}
}
}
@@ -132,7 +132,14 @@ namespace WorldPackets
uint32 Flags = 0; ///< enum WarbandGroupFlags { Collapsed = 1 }
int32 ContentSetID = 0;
std::vector<WarbandGroupMember> Members;
std::string_view Name;
std::string Name;
};
// Groups saved by CMSG_SETUP_WARBAND_GROUPS. Owned here so the next character
// enumeration can send them back. The packet itself only carries a view of this.
struct AccountWarbandGroups
{
std::vector<WarbandGroup> Groups;
};
class EnumCharactersResult final : public ServerPacket
@@ -977,6 +984,57 @@ namespace WorldPackets
WorldPacket const* Write() override;
};
// CMSG_GET_ACCOUNT_CHARACTER_LIST. 12.1.0.69587 body is a uint32 token plus one trailing zero byte.
class GetAccountCharacterList final : public ClientPacket
{
public:
explicit GetAccountCharacterList(WorldPacket&& packet) : ClientPacket(CMSG_GET_ACCOUNT_CHARACTER_LIST, std::move(packet)) {}
void Read() override;
uint32 Token = 0;
};
// SMSG_GET_ACCOUNT_CHARACTER_LIST_RESULT. Field order from a 12.1.0.69587 retail capture:
// token, count, then per character wow-account guid, player guid, virtual realm, race, class,
// sex, level, last-active unix time, content set, 6-bit name, 9-bit realm name. One trailing bit.
class GetAccountCharacterListResult final : public ServerPacket
{
public:
struct CharacterInfo
{
ObjectGuid WowAccount;
ObjectGuid Guid;
uint32 VirtualRealmAddress = 0;
uint8 RaceID = 0;
uint8 ClassID = 0;
uint8 SexID = 0;
uint8 ExperienceLevel = 0;
uint64 LastActiveTime = 0;
int32 ContentSetID = 0;
std::string Name;
std::string RealmName;
};
GetAccountCharacterListResult() : ServerPacket(SMSG_GET_ACCOUNT_CHARACTER_LIST_RESULT, 9) {}
WorldPacket const* Write() override;
uint32 Token = 0;
std::vector<CharacterInfo> Characters;
bool ConsoleCommand = false;
};
// CMSG_SETUP_WARBAND_GROUPS. 5-bit group count, then the same group layout EnumCharactersResult writes.
class SetupWarbandGroups final : public ClientPacket
{
public:
explicit SetupWarbandGroups(WorldPacket&& packet) : ClientPacket(CMSG_SETUP_WARBAND_GROUPS, std::move(packet)) {}
void Read() override;
std::vector<WarbandGroup> Groups;
};
//WowCommunity
}
}
+4 -4
View File
@@ -156,7 +156,7 @@ void OpcodeTable::InitializeClientOpcodes()
DEFINE_HANDLER(CMSG_ACTIVATE_SOULBIND, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleActivateSoulbind);
DEFINE_HANDLER(CMSG_ACTIVATE_TAXI, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleActivateTaxiOpcode);
DEFINE_HANDLER(CMSG_ADDON_LIST, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_ADD_ACCOUNT_COSMETIC, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_ADD_ACCOUNT_COSMETIC, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAddAccountCosmetic);
DEFINE_HANDLER(CMSG_ADD_BATTLENET_FRIEND, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_ADD_FRIEND, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAddFriendOpcode);
DEFINE_HANDLER(CMSG_ADD_IGNORE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAddIgnoreOpcode);
@@ -492,7 +492,7 @@ void OpcodeTable::InitializeClientOpcodes()
DEFINE_HANDLER(CMSG_GARRISON_START_MISSION, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleGarrisonStartMission);
DEFINE_HANDLER(CMSG_GARRISON_SWAP_BUILDINGS, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleGarrisonSwapBuildings);
DEFINE_HANDLER(CMSG_GENERATE_RANDOM_CHARACTER_NAME, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleRandomizeCharNameOpcode);
DEFINE_HANDLER(CMSG_GET_ACCOUNT_CHARACTER_LIST, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_GET_ACCOUNT_CHARACTER_LIST, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleGetAccountCharListOpcode);
DEFINE_HANDLER(CMSG_GET_ACCOUNT_NOTIFICATIONS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_GET_ALL_LICENSED_DECOR_QUANTITIES, STATUS_AUTHED, PROCESS_INPLACE, &WorldSession::HandleGetAllLicensedDecorQuantities);
DEFINE_HANDLER(CMSG_GET_AVAILABLE_INITIATIVE_REQUEST, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
@@ -1022,7 +1022,7 @@ void OpcodeTable::InitializeClientOpcodes()
DEFINE_HANDLER(CMSG_SEND_TEXT_EMOTE, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleTextEmoteOpcode);
DEFINE_HANDLER(CMSG_SERVER_TIME_OFFSET_REQUEST, STATUS_AUTHED, PROCESS_INPLACE, &WorldSession::HandleServerTimeOffsetRequest);
DEFINE_HANDLER(CMSG_SERVER_VALIDATION_SIGNATURE_REQUEST, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_SETUP_WARBAND_GROUPS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_SETUP_WARBAND_GROUPS, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetupWarbandGroups);
DEFINE_HANDLER(CMSG_SET_ACTION_BAR_TOGGLES, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetActionBarToggles);
DEFINE_HANDLER(CMSG_SET_ACTION_BUTTON, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetActionButtonOpcode);
DEFINE_HANDLER(CMSG_SET_ACTIVE_MOVER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetActiveMoverOpcode);
@@ -1650,7 +1650,7 @@ void OpcodeTable::InitializeServerOpcodes()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GARRISON_USE_RECALL_PORTAL_RESULT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GENERATE_RANDOM_CHARACTER_NAME_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GENERATE_SSO_TOKEN_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_ACCOUNT_CHARACTER_LIST_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_ACCOUNT_CHARACTER_LIST_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_ALL_LICENSED_DECOR_QUANTITIES_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_DECOR_REFUND_LIST_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_GARRISON_INFO_RESULT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
+2
View File
@@ -363,6 +363,7 @@ namespace WorldPackets
//WowCommunity
class SetupWarbandGroups;
class GetAccountCharacterList;
struct AccountWarbandGroups;
class ConvertTimerunningCharacter;
class EncounterJournalStartArathiRpe;
class GetRegionwideCharacterRestrictionAndMailData;
@@ -2772,6 +2773,7 @@ public:
// this stores the GUIDs of the characters who can login
// characters who failed on Player::BuildEnumData shouldn't login
GuidSet _legitCharacters;
std::unique_ptr<WorldPackets::Character::AccountWarbandGroups> _warbandGroups;
Unit* ValidateAndGetUnitBeingMoved(ObjectGuid guid, OpcodeClient opcode, bool forStatusAck) const;
ObjectGuid::LowType m_GUIDLow; // set logined or recently logout player (while m_playerRecentlyLogout set)
@@ -0,0 +1,41 @@
/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "WorldserverResourcesService.h"
#include "BattlenetRpcErrorCodes.h"
#include "Log.h"
namespace Battlenet::Services
{
WorldserverResourcesService::WorldserverResourcesService(WorldSession* session) : BaseService(session)
{
}
uint32 WorldserverResourcesService::HandleGetContentHandle(resources::v1::ContentHandleRequest const* request, ::bgs::protocol::ContentHandle* response, std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)>& /*continuation*/)
{
static constexpr char const* ShopContentHash = "\x57\x22\x12\xEC\x79\x41\x60\x53\x0C\xD5\x2E\xC4\x6E\x0D\xF2\x38\x03\x75\x7D\xCF\xF3\xAF\xF7\x95\x56\xBF\x85\x1A\xDC\x62\x5A\xAC";
TC_LOG_DEBUG("session.rpc", "[ResourcesService.GetContentHandle] program={} stream={} version={} -> serving shop2 content handle",
request->program(), request->stream(), request->version());
response->set_region(0x5553); // "US"
response->set_usage(0x70667479); // "pfty"
response->set_hash(ShopContentHash, 32);
response->set_proto_url("https://prod.depot.battle.net/${hash}.${usage}");
return ERROR_OK;
}
}
@@ -0,0 +1,37 @@
/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WORLDSERVER_RESOURCES_SERVICE_H
#define WORLDSERVER_RESOURCES_SERVICE_H
#include "WorldserverService.h"
#include "Client/resource_service.pb.h"
namespace Battlenet::Services
{
class WorldserverResourcesService : public WorldserverService<resources::v1::ResourcesService>
{
typedef WorldserverService<resources::v1::ResourcesService> BaseService;
public:
WorldserverResourcesService(WorldSession* session);
uint32 HandleGetContentHandle(resources::v1::ContentHandleRequest const* request, ::bgs::protocol::ContentHandle* response, std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)>& continuation) override;
};
}
#endif // WORLDSERVER_RESOURCES_SERVICE_H
@@ -16,6 +16,7 @@
*/
#include "WorldserverServiceDispatcher.h"
#include "WorldserverResourcesService.h"
Battlenet::WorldserverServiceDispatcher::WorldserverServiceDispatcher()
{
@@ -38,7 +39,7 @@ Battlenet::WorldserverServiceDispatcher::WorldserverServiceDispatcher()
AddService<WorldserverService<report::v1::ReportService>>();
AddService<WorldserverService<report::v2::ReportService>>();
AddService<WorldserverService<report::v3::client::ReportService>>();
AddService<WorldserverService<resources::v1::ResourcesService>>();
AddService<Services::WorldserverResourcesService>();
AddService<WorldserverService<whisper::v2::client::WhisperService>>();
}