diff options
20 files changed, 1117 insertions, 249 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index d4888150eb1..15e94f7bdd9 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -43,6 +43,7 @@ #include "ChatPackets.h" #include "ChatTextBuilder.h" #include "CinematicMgr.h" +#include "ClubUtils.h" #include "CombatLogPackets.h" #include "CombatPackets.h" #include "Common.h" @@ -17791,6 +17792,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol SetUpdateFieldValue(m_values.ModifyValue(&Player::m_playerData).ModifyValue(&UF::PlayerData::WowAccount), GetSession()->GetAccountGUID()); SetUpdateFieldValue(m_values.ModifyValue(&Player::m_playerData).ModifyValue(&UF::PlayerData::BnetAccount), GetSession()->GetBattlenetAccountGUID()); + SetUpdateFieldValue(m_values.ModifyValue(&Player::m_playerData).ModifyValue(&UF::PlayerData::GuildClubMemberID), Battlenet::Services::Clubs::CreateClubMemberId(guid)); if (!IsValidGender(fields.gender)) { diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index c36c3510919..db5f1b07806 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -24,9 +24,12 @@ #include "CharacterCache.h" #include "Chat.h" #include "ChatPackets.h" +#include "ClubMembershipService.h" +#include "ClubService.h" +#include "ClubUtils.h" #include "Config.h" -#include "DatabaseEnv.h" #include "DB2Stores.h" +#include "DatabaseEnv.h" #include "GameTime.h" #include "GuildMgr.h" #include "GuildPackets.h" @@ -40,6 +43,8 @@ #include "SocialMgr.h" #include "World.h" #include "WorldSession.h" +#include "club_listener.pb.h" +#include "club_membership_listener.pb.h" size_t const MAX_GUILD_BANK_TAB_TEXT_LEN = 500; @@ -1194,8 +1199,27 @@ void Guild::Disband() // Call scripts before guild data removed from database sScriptMgr->OnGuildDisband(this); - WorldPackets::Guild::GuildEventDisbanded packet; - BroadcastPacket(packet.Write()); + WorldPackets::Guild::GuildEventDisbanded guildEventDisbanded; + guildEventDisbanded.Write(); + + // Notify the members of club removal. + club::v1::UnsubscribeNotification unsubscribeNotification; + unsubscribeNotification.set_club_id(GetId()); + + BroadcastWorker([&](Player const* member) + { + member->SendDirectMessage(guildEventDisbanded.GetRawPacket()); + + // Unsubscribe the removed player from the club to ensure interface updates. + Battlenet::WorldserverService<club::v1::ClubListener>(member->GetSession()).OnUnsubscribe(&unsubscribeNotification, true, true); + + // Finally notify the client about leaving the club. + club::v1::membership::ClubRemovedNotification clubRemovedNotification; + clubRemovedNotification.set_allocated_member_id(Battlenet::Services::ClubMembershipService::CreateClubMemberId(member->GetGUID()).release()); + clubRemovedNotification.set_club_id(GetId()); + clubRemovedNotification.set_reason(club::v1::ClubRemovedReason::CLUB_REMOVED_REASON_DESTROYED_BY_MEMBER); + Battlenet::WorldserverService<club::v1::membership::ClubMembershipListener>(member->GetSession()).OnClubRemoved(&clubRemovedNotification, true, true); + }); CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); // Remove all members @@ -1333,6 +1357,7 @@ void Guild::HandleRoster(WorldSession* session) memberData.ClassID = member.GetClass(); memberData.Gender = member.GetGender(); memberData.RaceID = member.GetRace(); + memberData.GuildClubMemberID = Battlenet::Services::Clubs::CreateClubMemberId(member.GetGUID()); memberData.Authenticated = false; memberData.SorEligible = false; @@ -2356,11 +2381,20 @@ void Guild::SendEventNewLeader(Member* newLeader, Member* oldLeader, bool isSelf { WorldPackets::Guild::GuildEventNewLeader eventPacket; eventPacket.SelfPromoted = isSelfPromoted; + + club::v1::MemberRoleChangedNotification memberRoleChangeNotification; + memberRoleChangeNotification.set_club_id(GetId()); + if (newLeader) { eventPacket.NewLeaderGUID = newLeader->GetGUID(); eventPacket.NewLeaderName = newLeader->GetName(); eventPacket.NewLeaderVirtualRealmAddress = GetVirtualRealmAddress(); + + // Owner/GuildMaster role is always 1. + club::v1::RoleAssignment* newLeaderRoleAssignment = memberRoleChangeNotification.add_assignment(); + newLeaderRoleAssignment->set_allocated_member_id(Battlenet::Services::ClubMembershipService::CreateClubMemberId(newLeader->GetGUID()).release()); + newLeaderRoleAssignment->add_role(AsUnderlyingType(ClubRoleIdentifier::Owner)); } if (oldLeader) @@ -2368,9 +2402,21 @@ void Guild::SendEventNewLeader(Member* newLeader, Member* oldLeader, bool isSelf eventPacket.OldLeaderGUID = oldLeader->GetGUID(); eventPacket.OldLeaderName = oldLeader->GetName(); eventPacket.OldLeaderVirtualRealmAddress = GetVirtualRealmAddress(); + + // Non owner members in guilds get the lowest club/community role after a guild master change. + club::v1::RoleAssignment* oldLeaderRoleAssignment = memberRoleChangeNotification.add_assignment(); + oldLeaderRoleAssignment->set_allocated_member_id(Battlenet::Services::ClubMembershipService::CreateClubMemberId(oldLeader->GetGUID()).release()); + oldLeaderRoleAssignment->add_role(AsUnderlyingType(ClubRoleIdentifier::Member)); } - BroadcastPacket(eventPacket.Write()); + eventPacket.Write(); + + // We have to send old guild and new club packets so we use a custom broadcast loop here. + BroadcastWorker([&](Player const* member) + { + member->SendDirectMessage(eventPacket.GetRawPacket()); + Battlenet::WorldserverService<club::v1::ClubListener>(member->GetSession()).OnMemberRoleChanged(&memberRoleChangeNotification, true, true); + }); } void Guild::SendEventPlayerLeft(Member* leaver, Member* remover, bool isRemoved) const @@ -2388,7 +2434,46 @@ void Guild::SendEventPlayerLeft(Member* leaver, Member* remover, bool isRemoved) eventPacket.RemoverVirtualRealmAddress = GetVirtualRealmAddress(); } - BroadcastPacket(eventPacket.Write()); + eventPacket.Write(); + + Player* leaverPlayer = leaver->FindConnectedPlayer(); + + // Notify the removed member of club removal. + if (leaverPlayer) + { + leaverPlayer->SendDirectMessage(eventPacket.GetRawPacket()); + + // Unsubscribe the removed player from the club to ensure interface updates. + club::v1::UnsubscribeNotification unsubscribeNotification; + unsubscribeNotification.set_club_id(GetId()); + Battlenet::WorldserverService<club::v1::ClubListener>(leaverPlayer->GetSession()).OnUnsubscribe(&unsubscribeNotification, true, true); + + // Finally notify the client about leaving the club. + club::v1::membership::ClubRemovedNotification clubRemovedNotification; + clubRemovedNotification.set_club_id(GetId()); + clubRemovedNotification.set_reason(isRemoved + ? club::v1::ClubRemovedReason::CLUB_REMOVED_REASON_MEMBER_KICKED + : club::v1::ClubRemovedReason::CLUB_REMOVED_REASON_MEMBER_LEFT); + clubRemovedNotification.set_allocated_member_id(Battlenet::Services::ClubMembershipService::CreateClubMemberId(leaver->GetGUID()).release()); + Battlenet::WorldserverService<club::v1::membership::ClubMembershipListener>(leaverPlayer->GetSession()).OnClubRemoved(&clubRemovedNotification, true, true); + } + + club::v1::MemberRemovedNotification memberRemovedNotification; + memberRemovedNotification.set_club_id(GetId()); + + club::v1::MemberRemovedAssignment* removedMemberAssignment = memberRemovedNotification.add_member(); + removedMemberAssignment->set_allocated_id(Battlenet::Services::ClubMembershipService::CreateClubMemberId(leaver->GetGUID()).release()); + removedMemberAssignment->set_reason(isRemoved + ? club::v1::ClubRemovedReason::CLUB_REMOVED_REASON_MEMBER_KICKED + : club::v1::ClubRemovedReason::CLUB_REMOVED_REASON_MEMBER_LEFT); + + // We have to send old guild and new club packets so we use a custom broadcast loop here. + BroadcastWorker([&](Player const* member) + { + // Notify other guild members. + member->SendDirectMessage(eventPacket.GetRawPacket()); + Battlenet::WorldserverService<::bgs::protocol::club::v1::ClubListener>(member->GetSession()).OnMemberRemoved(&memberRemovedNotification, true, true); + }, leaverPlayer); } void Guild::SendEventPresenceChanged(WorldSession* session, bool loggedOn, bool broadcast) const @@ -2819,7 +2904,58 @@ bool Guild::AddMember(CharacterDatabaseTransaction trans, ObjectGuid guid, Optio joinNotificationPacket.Guid = guid; joinNotificationPacket.Name = name; joinNotificationPacket.VirtualRealmAddress = GetVirtualRealmAddress(); - BroadcastPacket(joinNotificationPacket.Write()); + joinNotificationPacket.Write(); + + // Notify the added member with new club data. + if (player) + { + player->SendDirectMessage(joinNotificationPacket.GetRawPacket()); + + club::v1::membership::ClubAddedNotification clubAddedNotification; + clubAddedNotification.mutable_membership()->set_allocated_member_id(Battlenet::Services::ClubMembershipService::CreateClubMemberId(guid).release()); + + club::v1::ClubDescription* guildClub = clubAddedNotification.mutable_membership()->mutable_club(); + guildClub->set_id(GetId()); + guildClub->set_allocated_type(Battlenet::Services::ClubService::CreateGuildClubType().release()); + guildClub->set_name(GetName()); + guildClub->set_privacy_level(club::v1::PrivacyLevel::PRIVACY_LEVEL_OPEN); + guildClub->set_visibility_level(club::v1::VISIBILITY_LEVEL_PRIVATE); + guildClub->set_member_count(GetMembersCount()); + + // Set the club owner, guild master in this case. + club::v1::MemberDescription* guildLeaderDescription = guildClub->add_leader(); + guildLeaderDescription->set_allocated_id(Battlenet::Services::ClubMembershipService::CreateClubMemberId(GetLeaderGUID()).release()); + + // Date is in microseconds. + guildClub->set_creation_time( + std::chrono::duration_cast<std::chrono::microseconds>(SystemTimePoint::clock::from_time_t(GetCreatedDate()).time_since_epoch()).count()); + guildClub->set_timezone(""); + guildClub->set_locale(""); + + Battlenet::WorldserverService<club::v1::membership::ClubMembershipListener>(player->GetSession()).OnClubAdded(&clubAddedNotification, true, true); + } + + club::v1::MemberAddedNotification memberAddedNotification; + memberAddedNotification.set_club_id(GetId()); + + club::v1::Member* addedMember = memberAddedNotification.add_member(); + addedMember->set_allocated_id(Battlenet::Services::ClubMembershipService::CreateClubMemberId(guid).release()); + if (HasAnyRankRight(member.GetRankId(), GuildRankRights(GR_RIGHT_OFFCHATLISTEN | GR_RIGHT_OFFCHATSPEAK))) + addedMember->add_role(AsUnderlyingType(ClubRoleIdentifier::Moderator)); + else + addedMember->add_role(AsUnderlyingType(ClubRoleIdentifier::Member)); + addedMember->set_presence_level(club::v1::PresenceLevel::PRESENCE_LEVEL_RICH); + addedMember->set_whisper_level(club::v1::WhisperLevel::WHISPER_LEVEL_OPEN); + addedMember->set_note(""); + addedMember->set_active(member.IsOnline()); + + // We have to send old guild and new club packets so we use a custom broadcast loop here. + BroadcastWorker([&](Player const* otherMember) + { + // Notify other online guild members. + otherMember->SendDirectMessage(joinNotificationPacket.GetRawPacket()); + Battlenet::WorldserverService<club::v1::ClubListener>(otherMember->GetSession()).OnMemberAdded(&memberAddedNotification, true, true); + }, player); // Call scripts if member was succesfully added (and stored to database) sScriptMgr->OnGuildAddMember(this, player, AsUnderlyingType(*rankId)); @@ -3002,6 +3138,11 @@ bool Guild::_HasRankRight(Player const* player, uint32 right) const return false; } +bool Guild::HasAnyRankRight(GuildRankId rankId, GuildRankRights rights) const +{ + return (_GetRankRights(rankId) & rights) != GR_RIGHT_NONE; +} + void Guild::_DeleteMemberFromDB(CharacterDatabaseTransaction trans, ObjectGuid::LowType lowguid) { CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_MEMBER); @@ -3579,7 +3720,25 @@ void Guild::SendGuildRanksUpdate(ObjectGuid setterGuid, ObjectGuid targetGuid, G rankChange.Other = targetGuid; rankChange.RankID = AsUnderlyingType(rank); rankChange.Promote = (rank < member->GetRankId()); - BroadcastPacket(rankChange.Write()); + rankChange.Write(); + + club::v1::MemberRoleChangedNotification memberRoleChangeNotification; + memberRoleChangeNotification.set_club_id(GetId()); + + club::v1::RoleAssignment* changedRoleAssignment = memberRoleChangeNotification.add_assignment(); + changedRoleAssignment->set_allocated_member_id(Battlenet::Services::ClubMembershipService::CreateClubMemberId(targetGuid).release()); + if (rank == GuildRankId::GuildMaster) + changedRoleAssignment->add_role(AsUnderlyingType(ClubRoleIdentifier::Owner)); + else if (HasAnyRankRight(rank, GuildRankRights(GR_RIGHT_OFFCHATLISTEN | GR_RIGHT_OFFCHATSPEAK))) + changedRoleAssignment->add_role(AsUnderlyingType(ClubRoleIdentifier::Moderator)); + else + changedRoleAssignment->add_role(AsUnderlyingType(ClubRoleIdentifier::Member)); + + BroadcastWorker([&](Player const* memberPlayer) + { + memberPlayer->SendDirectMessage(rankChange.GetRawPacket()); + Battlenet::WorldserverService<club::v1::ClubListener>(memberPlayer->GetSession()).OnMemberRoleChanged(&memberRoleChangeNotification, true, true); + }); CharacterDatabaseTransaction trans; member->ChangeRank(trans, rank); diff --git a/src/server/game/Guilds/Guild.h b/src/server/game/Guilds/Guild.h index f8aacf775c5..10384f091d1 100644 --- a/src/server/game/Guilds/Guild.h +++ b/src/server/game/Guilds/Guild.h @@ -73,6 +73,24 @@ enum GuildMemberData GUILD_MEMBER_DATA_LEVEL, }; +// Base Club/Community roles. Do not change. +enum class ClubRoleIdentifier : uint32 +{ + Owner = 1, + Leader = 2, + Moderator = 3, + Member = 4 +}; + +// Base Club/Community chat stream types. Do not change. +enum class ClubStreamType : uint32 +{ + General = 0, + Guild = 1, + Officer = 2, + Other = 3 +}; + enum class GuildRankId : uint8 { GuildMaster = 0 @@ -308,7 +326,7 @@ using SlotIds = std::set<uint8>; class TC_GAME_API Guild { - private: + public: // Class representing guild member class Member { @@ -401,6 +419,7 @@ class TC_GAME_API Guild uint32 m_weekReputation; }; + private: // Base class for event entries class LogEntry { @@ -813,10 +832,10 @@ class TC_GAME_API Guild void MassInviteToEvent(WorldSession* session, uint32 minLevel, uint32 maxLevel, GuildRankOrder minRank); template<class Do> - void BroadcastWorker(Do& _do, Player* except = nullptr) + void BroadcastWorker(Do&& _do, Player const* except = nullptr) const { - for (auto itr = m_members.begin(); itr != m_members.end(); ++itr) - if (Player* player = itr->second.FindConnectedPlayer()) + for (auto const& [_, member] : m_members) + if (Player* player = member.FindConnectedPlayer()) if (player != except) _do(player); } @@ -828,6 +847,7 @@ class TC_GAME_API Guild bool ChangeMemberRank(CharacterDatabaseTransaction trans, ObjectGuid guid, GuildRankId newRank); bool IsMember(ObjectGuid guid) const; uint32 GetMembersCount() const { return uint32(m_members.size()); } + std::unordered_map<ObjectGuid, Member> const& GetMembers() const { return m_members; } uint64 GetMemberAvailableMoneyForRepairItems(ObjectGuid guid) const; std::vector<Player*> GetMembersTrackingCriteria(uint32 criteriaId) const; @@ -881,19 +901,24 @@ class TC_GAME_API Guild RankInfo const* GetRankInfo(GuildRankOrder rankOrder) const; RankInfo* GetRankInfo(GuildRankOrder rankOrder); bool _HasRankRight(Player const* player, uint32 right) const; + public: + bool HasAnyRankRight(GuildRankId rankId, GuildRankRights rights) const; + private: inline GuildRankId _GetLowestRankId() const { return m_ranks.back().GetId(); } inline uint8 _GetPurchasedTabsSize() const { return uint8(m_bankTabs.size()); } inline BankTab* GetBankTab(uint8 tabId) { return tabId < m_bankTabs.size() ? &m_bankTabs[tabId] : nullptr; } inline BankTab const* GetBankTab(uint8 tabId) const { return tabId < m_bankTabs.size() ? &m_bankTabs[tabId] : nullptr; } + public: inline Member const* GetMember(ObjectGuid const& guid) const { auto itr = m_members.find(guid); return (itr != m_members.end()) ? &itr->second : nullptr; } + private: inline Member* GetMember(ObjectGuid const& guid) { auto itr = m_members.find(guid); diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index bc673388aac..149b0ad914a 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -1469,6 +1469,15 @@ void WorldSession::SendFeatureSystemStatus() features.VoiceEnabled = false; features.BrowserEnabled = false; // Has to be false, otherwise client will crash if "Customer Support" is opened + // Enable guilds only. + // This is required to restore old guild channel behavior for GMs. + // The new club streams do not support sending messages through the guild channel when you are not in a guild. + features.ClubsEnabled = true; + features.ClubsBattleNetClubTypeAllowed = false; + features.ClubsCharacterClubTypeAllowed = false; + features.ClubsPresenceUpdateEnabled = true; + features.HiddenUIClubsPresenceUpdateTimer = 60000; + features.EuropaTicketSystemStatus.emplace(); features.EuropaTicketSystemStatus->ThrottleState.MaxTries = 10; features.EuropaTicketSystemStatus->ThrottleState.PerMilliseconds = 60000; diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp index 5111e6f03ac..e1c3b74622c 100644 --- a/src/server/game/Handlers/ChatHandler.cpp +++ b/src/server/game/Handlers/ChatHandler.cpp @@ -143,15 +143,15 @@ void WorldSession::HandleChatMessageEmoteOpcode(WorldPackets::Chat::ChatMessageE HandleChatMessage(CHAT_MSG_EMOTE, LANG_UNIVERSAL, chatMessageEmote.Text); } -void WorldSession::HandleChatMessage(ChatMsg type, Language lang, std::string msg, std::string target /*= ""*/, Optional<ObjectGuid> channelGuid /*= {}*/) +ChatMessageResult WorldSession::HandleChatMessage(ChatMsg type, Language lang, std::string msg, std::string target /*= ""*/, Optional<ObjectGuid> channelGuid /*= {}*/) { Player* sender = GetPlayer(); - if (lang == LANG_UNIVERSAL && type != CHAT_MSG_EMOTE) + if (lang == LANG_UNIVERSAL && type != CHAT_MSG_EMOTE && type != CHAT_MSG_GUILD && type != CHAT_MSG_OFFICER) { TC_LOG_ERROR("entities.player.cheat", "CMSG_MESSAGECHAT: Possible hacking-attempt: {} tried to send a message in universal language", GetPlayerInfo()); SendNotification(LANG_UNKNOWN_LANGUAGE); - return; + return ChatMessageResult::DisallowedLanguage; } // prevent talking at unknown language (cheating) @@ -159,7 +159,7 @@ void WorldSession::HandleChatMessage(ChatMsg type, Language lang, std::string ms if (languageData.begin() == languageData.end()) { SendNotification(LANG_UNKNOWN_LANGUAGE); - return; + return ChatMessageResult::InvalidLanguage; } if (std::none_of(languageData.begin(), languageData.end(), @@ -169,7 +169,7 @@ void WorldSession::HandleChatMessage(ChatMsg type, Language lang, std::string ms if (!sender->HasAuraTypeWithMiscvalue(SPELL_AURA_COMPREHEND_LANGUAGE, lang)) { SendNotification(LANG_NOT_LEARNED_LANGUAGE); - return; + return ChatMessageResult::LanguageNotLearned; } } @@ -213,7 +213,7 @@ void WorldSession::HandleChatMessage(ChatMsg type, Language lang, std::string ms { std::string timeStr = secsToTimeString(m_muteTime - GameTime::GetGameTime()); SendNotification(GetTrinityString(LANG_WAIT_BEFORE_SPEAKING), timeStr.c_str()); - return; + return ChatMessageResult::Muted; } if (type != CHAT_MSG_AFK && type != CHAT_MSG_DND) @@ -222,25 +222,25 @@ void WorldSession::HandleChatMessage(ChatMsg type, Language lang, std::string ms if (sender->HasAura(GM_SILENCE_AURA) && type != CHAT_MSG_WHISPER) { SendNotification(GetTrinityString(LANG_GM_SILENCE), sender->GetName().c_str()); - return; + return ChatMessageResult::SilencedByGM; } if (msg.size() > 511) - return; + return ChatMessageResult::MessageTooLong; if (msg.empty()) - return; + return ChatMessageResult::MessageEmpty; if (ChatHandler(this).ParseCommands(msg.c_str())) - return; + return ChatMessageResult::HandledCommand; // do message validity checks if (!ValidateMessage(GetPlayer(), msg)) - return; + return ChatMessageResult::MessageHasInvalidCharacters; // validate hyperlinks if (!ValidateHyperlinksAndMaybeKick(msg)) - return; + return ChatMessageResult::MalformedHyperlinks; switch (type) { @@ -248,12 +248,12 @@ void WorldSession::HandleChatMessage(ChatMsg type, Language lang, std::string ms { // Prevent cheating if (!sender->IsAlive()) - return; + return ChatMessageResult::PlayerDead; if (sender->GetLevel() < sWorld->getIntConfig(CONFIG_CHAT_SAY_LEVEL_REQ)) { SendNotification(GetTrinityString(LANG_SAY_REQ), sWorld->getIntConfig(CONFIG_CHAT_SAY_LEVEL_REQ)); - return; + return ChatMessageResult::LevelTooLow; } sender->Say(msg, lang); @@ -263,12 +263,12 @@ void WorldSession::HandleChatMessage(ChatMsg type, Language lang, std::string ms { // Prevent cheating if (!sender->IsAlive()) - return; + return ChatMessageResult::PlayerDead; if (sender->GetLevel() < sWorld->getIntConfig(CONFIG_CHAT_EMOTE_LEVEL_REQ)) { SendNotification(GetTrinityString(LANG_SAY_REQ), sWorld->getIntConfig(CONFIG_CHAT_EMOTE_LEVEL_REQ)); - return; + return ChatMessageResult::LevelTooLow; } sender->TextEmote(msg); @@ -278,12 +278,12 @@ void WorldSession::HandleChatMessage(ChatMsg type, Language lang, std::string ms { // Prevent cheating if (!sender->IsAlive()) - return; + return ChatMessageResult::PlayerDead; if (sender->GetLevel() < sWorld->getIntConfig(CONFIG_CHAT_YELL_LEVEL_REQ)) { SendNotification(GetTrinityString(LANG_SAY_REQ), sWorld->getIntConfig(CONFIG_CHAT_YELL_LEVEL_REQ)); - return; + return ChatMessageResult::LevelTooLow; } sender->Yell(msg, lang); @@ -304,7 +304,7 @@ void WorldSession::HandleChatMessage(ChatMsg type, Language lang, std::string ms if (!receiver || (lang != LANG_ADDON && !receiver->isAcceptWhispers() && receiver->GetSession()->HasPermission(rbac::RBAC_PERM_CAN_FILTER_WHISPERS) && !receiver->IsInWhisperWhiteList(sender->GetGUID()))) { SendChatPlayerNotfoundNotice(target); - return; + return ChatMessageResult::NoWhisperTarget; } // Apply checks only if receiver is not already in whitelist and if receiver is not a GM with ".whisper on" @@ -313,20 +313,20 @@ void WorldSession::HandleChatMessage(ChatMsg type, Language lang, std::string ms if (!sender->IsGameMaster() && sender->GetLevel() < sWorld->getIntConfig(CONFIG_CHAT_WHISPER_LEVEL_REQ)) { SendNotification(GetTrinityString(LANG_WHISPER_REQ), sWorld->getIntConfig(CONFIG_CHAT_WHISPER_LEVEL_REQ)); - return; + return ChatMessageResult::LevelTooLow; } if (GetPlayer()->GetEffectiveTeam() != receiver->GetEffectiveTeam() && !HasPermission(rbac::RBAC_PERM_TWO_SIDE_INTERACTION_CHAT)) { SendChatPlayerNotfoundNotice(target); - return; + return ChatMessageResult::WhisperTargetWrongFaction; } } if (GetPlayer()->HasAura(1852) && !receiver->IsGameMaster()) { SendNotification(GetTrinityString(LANG_GM_SILENCE), GetPlayer()->GetName().c_str()); - return; + return ChatMessageResult::SilencedByGM; } // If player is a Gamemaster and doesn't accept whisper, we auto-whitelist every player that the Gamemaster is talking to @@ -346,7 +346,7 @@ void WorldSession::HandleChatMessage(ChatMsg type, Language lang, std::string ms { group = sender->GetGroup(); if (!group || group->isBGGroup()) - return; + return ChatMessageResult::NotInGroup; } if (group->IsLeader(GetPlayer()->GetGUID())) @@ -389,7 +389,7 @@ void WorldSession::HandleChatMessage(ChatMsg type, Language lang, std::string ms { Group* group = GetPlayer()->GetGroup(); if (!group || !group->isRaidGroup() || group->isBGGroup()) - return; + return ChatMessageResult::NotInGroup; if (group->IsLeader(GetPlayer()->GetGUID())) type = CHAT_MSG_RAID_LEADER; @@ -404,8 +404,16 @@ void WorldSession::HandleChatMessage(ChatMsg type, Language lang, std::string ms case CHAT_MSG_RAID_WARNING: { Group* group = GetPlayer()->GetGroup(); - if (!group || !(group->isRaidGroup() || sWorld->getBoolConfig(CONFIG_CHAT_PARTY_RAID_WARNINGS)) || !(group->IsLeader(GetPlayer()->GetGUID()) || group->IsAssistant(GetPlayer()->GetGUID())) || group->isBGGroup()) - return; + if (!group) + return ChatMessageResult::NotInGroup; + + if (group->isRaidGroup()) + { + if (!group->IsLeader(GetPlayer()->GetGUID()) && !group->IsAssistant(GetPlayer()->GetGUID())) + return ChatMessageResult::NotLeaderOrAssistant; + } + else if (!sWorld->getBoolConfig(CONFIG_CHAT_PARTY_RAID_WARNINGS)) + return ChatMessageResult::RaidWarningInPartyDisabled; sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); @@ -422,7 +430,7 @@ void WorldSession::HandleChatMessage(ChatMsg type, Language lang, std::string ms if (sender->GetLevel() < sWorld->getIntConfig(CONFIG_CHAT_CHANNEL_LEVEL_REQ)) { SendNotification(GetTrinityString(LANG_CHANNEL_REQ), sWorld->getIntConfig(CONFIG_CHAT_CHANNEL_LEVEL_REQ)); - return; + return ChatMessageResult::LevelTooLow; } } @@ -433,7 +441,7 @@ void WorldSession::HandleChatMessage(ChatMsg type, Language lang, std::string ms { if (ChatChannelsEntry const* chatChannel = sChatChannelsStore.LookupEntry(chn->GetChannelId())) if (chatChannel->GetFlags().HasFlag(ChatChannelFlags::ReadOnly)) - return; + return ChatMessageResult::ChannelIsReadOnly; sScriptMgr->OnPlayerChat(sender, type, lang, msg, chn); chn->Say(sender->GetGUID(), msg, lang); @@ -444,7 +452,7 @@ void WorldSession::HandleChatMessage(ChatMsg type, Language lang, std::string ms { Group* group = GetPlayer()->GetGroup(); if (!group) - return; + return ChatMessageResult::NotInGroup; if (group->IsLeader(GetPlayer()->GetGUID())) type = CHAT_MSG_INSTANCE_CHAT_LEADER; @@ -460,6 +468,8 @@ void WorldSession::HandleChatMessage(ChatMsg type, Language lang, std::string ms TC_LOG_ERROR("network", "CHAT: unknown message type {}, lang: {}", type, lang); break; } + + return ChatMessageResult::Ok; } void WorldSession::HandleChatAddonMessageOpcode(WorldPackets::Chat::ChatAddonMessage& chatAddonMessage) diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 7b34e1a08a1..2ff3a7c77b5 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -5980,6 +5980,29 @@ enum ChatLinkColors : uint32 CHAT_LINK_COLOR_TRANSMOG = 0xffff80ff, }; +enum class ChatMessageResult : uint32 +{ + Ok, + HandledCommand, + DisallowedLanguage, + InvalidLanguage, + LanguageNotLearned, + Muted, + SilencedByGM, + MessageTooLong, + MessageEmpty, + MessageHasInvalidCharacters, + MalformedHyperlinks, + PlayerDead, + LevelTooLow, + NoWhisperTarget, + WhisperTargetWrongFaction, + NotInGroup, + NotLeaderOrAssistant, + RaidWarningInPartyDisabled, + ChannelIsReadOnly +}; + // Values from ItemPetFood (power of (value-1) used for compare with CreatureFamilyEntry.PetFoodMask enum PetDiet { diff --git a/src/server/game/Server/Packets/BattlenetPackets.cpp b/src/server/game/Server/Packets/BattlenetPackets.cpp index f72ab913fd2..95b740fbd65 100644 --- a/src/server/game/Server/Packets/BattlenetPackets.cpp +++ b/src/server/game/Server/Packets/BattlenetPackets.cpp @@ -16,6 +16,7 @@ */ #include "BattlenetPackets.h" +#include "PacketUtilities.h" ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Battlenet::MethodCall const& method) { @@ -78,9 +79,15 @@ void WorldPackets::Battlenet::Request::Read() _worldPacket >> Method; _worldPacket >> protoSize; - Data.Resize(protoSize); - _worldPacket.read(Data.GetWritePointer(), Data.GetRemainingSpace()); - Data.WriteCompleted(protoSize); + if (protoSize > 0xFFFF) + throw PacketArrayMaxCapacityException(protoSize, 0xFFFF); + + if (protoSize) + { + Data.Resize(protoSize); + _worldPacket.read(Data.GetWritePointer(), Data.GetRemainingSpace()); + Data.WriteCompleted(protoSize); + } } void WorldPackets::Battlenet::ChangeRealmTicket::Read() diff --git a/src/server/game/Server/Packets/CharacterPackets.cpp b/src/server/game/Server/Packets/CharacterPackets.cpp index 2a14e107077..cb89c8c3045 100644 --- a/src/server/game/Server/Packets/CharacterPackets.cpp +++ b/src/server/game/Server/Packets/CharacterPackets.cpp @@ -16,6 +16,7 @@ */ #include "CharacterPackets.h" +#include "ClubUtils.h" #include "DB2Stores.h" #include "Field.h" #include "ObjectMgr.h" @@ -103,6 +104,7 @@ EnumCharactersResult::CharacterInfo::CharacterInfo(Field* fields) // "character_declinedname.genitive" Guid = ObjectGuid::Create<HighGuid::Player>(fields[0].GetUInt64()); + GuildClubMemberID = ::Battlenet::Services::Clubs::CreateClubMemberId(Guid); Name = fields[1].GetString(); RaceID = fields[2].GetUInt8(); ClassID = fields[3].GetUInt8(); diff --git a/src/server/game/Server/Packets/QueryPackets.cpp b/src/server/game/Server/Packets/QueryPackets.cpp index ccc9ec8ba94..10a1b336a5f 100644 --- a/src/server/game/Server/Packets/QueryPackets.cpp +++ b/src/server/game/Server/Packets/QueryPackets.cpp @@ -18,6 +18,7 @@ #include "QueryPackets.h" #include "BattlenetAccountMgr.h" #include "CharacterCache.h" +#include "ClubUtils.h" #include "ObjectMgr.h" #include "Player.h" #include "World.h" @@ -200,6 +201,7 @@ bool PlayerGuidLookupData::Initialize(ObjectGuid const& guid, Player const* play IsDeleted = characterInfo->IsDeleted; GuidActual = guid; + GuildClubMemberID = ::Battlenet::Services::Clubs::CreateClubMemberId(guid); VirtualRealmAddress = GetVirtualRealmAddress(); return true; diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index a1b5b5524aa..5b7257367f2 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -1552,7 +1552,7 @@ class TC_GAME_API WorldSession void HandleChatMessageOpcode(WorldPackets::Chat::ChatMessage& chatMessage); void HandleChatMessageWhisperOpcode(WorldPackets::Chat::ChatMessageWhisper& chatMessageWhisper); void HandleChatMessageChannelOpcode(WorldPackets::Chat::ChatMessageChannel& chatMessageChannel); - void HandleChatMessage(ChatMsg type, Language lang, std::string msg, std::string target = "", Optional<ObjectGuid> channelGuid = {}); + ChatMessageResult HandleChatMessage(ChatMsg type, Language lang, std::string msg, std::string target = "", Optional<ObjectGuid> channelGuid = {}); void HandleChatAddonMessageOpcode(WorldPackets::Chat::ChatAddonMessage& chatAddonMessage); void HandleChatAddonMessageTargetedOpcode(WorldPackets::Chat::ChatAddonMessageTargeted& chatAddonMessageTargeted); void HandleChatAddonMessage(ChatMsg type, std::string prefix, std::string text, bool isLogged, std::string target = "", Optional<ObjectGuid> channelGuid = {}); diff --git a/src/server/game/Services/ClubMembershipService.cpp b/src/server/game/Services/ClubMembershipService.cpp new file mode 100644 index 00000000000..419d56f29ef --- /dev/null +++ b/src/server/game/Services/ClubMembershipService.cpp @@ -0,0 +1,84 @@ +/* + * 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 "ClubMembershipService.h" +#include "BattlenetRpcErrorCodes.h" +#include "CharacterCache.h" +#include "ClubService.h" +#include "ClubUtils.h" +#include "Guild.h" +#include "Player.h" + +namespace Battlenet::Services +{ +ClubMembershipService::ClubMembershipService(WorldSession* session) : BaseService(session) { } + +uint32 ClubMembershipService::HandleSubscribe(club::v1::membership::SubscribeRequest const* /*request*/, club::v1::membership::SubscribeResponse* response, + std::function<void(ServiceBase*, uint32, google::protobuf::Message const*)>& /*continuation*/) +{ + Player const* player = _session->GetPlayer(); + + if (!player) + return ERROR_INTERNAL; + + Guild const* guild = player->GetGuild(); + + if (!guild) + return ERROR_OK; + + club::v1::ClubMembershipDescription* description = response->mutable_state()->add_description(); + description->set_allocated_member_id(CreateClubMemberId(player->GetGUID()).release()); + + club::v1::ClubDescription* club = description->mutable_club(); + club->set_id(guild->GetId()); + club->set_allocated_type(ClubService::CreateGuildClubType().release()); + club->set_name(guild->GetName()); + club->set_privacy_level(club::v1::PrivacyLevel::PRIVACY_LEVEL_OPEN); + club->set_visibility_level(club::v1::VISIBILITY_LEVEL_PRIVATE); + club->set_member_count(guild->GetMembersCount()); + club->set_creation_time( + std::chrono::duration_cast<std::chrono::microseconds>(SystemTimePoint::clock::from_time_t(guild->GetCreatedDate()).time_since_epoch()).count()); + + // Not setting these can cause issues. + club->set_timezone(""); + club->set_locale(""); + + club::v1::MemberDescription* leader = club->add_leader(); + + leader->set_allocated_id(CreateClubMemberId(guild->GetLeaderGUID()).release()); + + response->mutable_state()->mutable_mention_view()->set_last_read_time(0); + response->mutable_state()->mutable_mention_view()->set_last_message_time(0); + + return ERROR_OK; +} + +uint32 ClubMembershipService::HandleUnsubscribe(club::v1::membership::UnsubscribeRequest const* /*request*/, NoData* /*response*/, + std::function<void(ServiceBase*, uint32, google::protobuf::Message const*)>& /*continuation*/) +{ + // We just have to signal the client that the unsubscribe request came through. + return ERROR_OK; +} + +std::unique_ptr<club::v1::MemberId> ClubMembershipService::CreateClubMemberId(ObjectGuid guid) +{ + std::unique_ptr<club::v1::MemberId> id = std::make_unique<club::v1::MemberId>(); + id->mutable_account_id()->set_id(sCharacterCache->GetCharacterAccountIdByGuid(guid)); + id->set_unique_id(Clubs::CreateClubMemberId(guid)); + return id; +} +} diff --git a/src/server/game/Services/ClubMembershipService.h b/src/server/game/Services/ClubMembershipService.h new file mode 100644 index 00000000000..f914f8e25cd --- /dev/null +++ b/src/server/game/Services/ClubMembershipService.h @@ -0,0 +1,40 @@ +/* + * 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 ClubMembershipService_h__ +#define ClubMembershipService_h__ + +#include "WorldserverService.h" +#include "club_membership_service.pb.h" + +namespace Battlenet::Services +{ +class ClubMembershipService : public WorldserverService<club::v1::membership::ClubMembershipService> +{ + typedef WorldserverService<club::v1::membership::ClubMembershipService> BaseService; + +public: + ClubMembershipService(WorldSession* session); + + uint32 HandleSubscribe(club::v1::membership::SubscribeRequest const* request, club::v1::membership::SubscribeResponse* response, std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)>& continuation) override; + uint32 HandleUnsubscribe(club::v1::membership::UnsubscribeRequest const* request, NoData* response, std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)>& continuation) override; + + static std::unique_ptr<club::v1::MemberId> CreateClubMemberId(ObjectGuid guid); +}; +} + +#endif // ClubMembershipService_h__ diff --git a/src/server/game/Services/ClubService.cpp b/src/server/game/Services/ClubService.cpp new file mode 100644 index 00000000000..99df493c2c3 --- /dev/null +++ b/src/server/game/Services/ClubService.cpp @@ -0,0 +1,391 @@ +/* + * 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 "ClubService.h" +#include "BattlenetRpcErrorCodes.h" +#include "ClubMembershipService.h" +#include "GameTime.h" +#include "Guild.h" +#include "Player.h" +#include "SocialMgr.h" +#include "club_listener.pb.h" + +namespace Battlenet::Services +{ +ClubService::ClubService(WorldSession* session) : BaseService(session) { } + +uint32 ClubService::HandleGetClubType(club::v1::GetClubTypeRequest const* request, club::v1::GetClubTypeResponse* response, + std::function<void(ServiceBase*, uint32, google::protobuf::Message const*)>& /*continuation*/) +{ + // We only support guilds for now. + if (request->type().name() == "guild") + { + response->set_allocated_type(CreateGuildClubType().release()); + return ERROR_OK; + } + + return ERROR_NOT_IMPLEMENTED; +} + +uint32 ClubService::HandleSubscribe(club::v1::SubscribeRequest const* /*request*/, NoData* /*response*/, + std::function<void(ServiceBase*, uint32, google::protobuf::Message const*)>& /*continuation*/) +{ + Player* player = _session->GetPlayer(); + + if (!player) + return ERROR_INTERNAL; + + Guild const* guild = player->GetGuild(); + + if (!guild) + return ERROR_CLUB_NO_CLUB; + + // Subscibe the client to it's own guild club. + club::v1::SubscribeNotification subscribeNotification; + + Guild::Member const* guildMember = guild->GetMember(player->GetGUID()); + + if (!guildMember) + return ERROR_CLUB_NOT_MEMBER; + + Guild::Member const* guildLeader = guild->GetMember(guild->GetLeaderGUID()); + + if (!guildLeader) + return ERROR_CLUB_NO_SUCH_MEMBER; + + subscribeNotification.set_club_id(guild->GetId()); + subscribeNotification.set_allocated_agent_id(ClubMembershipService::CreateClubMemberId(player->GetGUID()).release()); + + club::v1::Club* guildClub = subscribeNotification.mutable_club(); + + guildClub->set_id(guild->GetId()); + guildClub->set_allocated_type(CreateGuildClubType().release()); + guildClub->set_name(guild->GetName()); + + // These are not related to normal guild functionality so we hardcode them for now. + guildClub->set_privacy_level(club::v1::PrivacyLevel::PRIVACY_LEVEL_OPEN); + guildClub->set_visibility_level(club::v1::VISIBILITY_LEVEL_PRIVATE); + + guildClub->set_member_count(guild->GetMembersCount()); + + // Set the club leader, guild master in this case. + club::v1::MemberDescription* guildLeaderDescription = guildClub->add_leader(); + + guildLeaderDescription->mutable_id()->mutable_account_id()->set_id(guildLeader->GetAccountId()); + guildLeaderDescription->mutable_id()->set_unique_id(guildLeader->GetGUID().GetCounter()); + + club::v1::Member* subscriber = subscribeNotification.mutable_member(); + + // The member sending the notification data. + subscriber->set_allocated_id(ClubMembershipService::CreateClubMemberId(player->GetGUID()).release()); + + // Community/Club default roles have slightly different values. + // Also this is required to set the current leader/guild master symbol in the interface. + // 1 = Owner, 4 = Member. Once communities are fully implemented these will go into a new database table. + if (guildMember->IsRank(GuildRankId::GuildMaster)) + subscriber->add_role(AsUnderlyingType(ClubRoleIdentifier::Owner)); + else if (guild->HasAnyRankRight(guildMember->GetRankId(), GuildRankRights(GR_RIGHT_OFFCHATLISTEN | GR_RIGHT_OFFCHATSPEAK))) + subscriber->add_role(AsUnderlyingType(ClubRoleIdentifier::Moderator)); + else + subscriber->add_role(AsUnderlyingType(ClubRoleIdentifier::Member)); + + subscriber->set_presence_level(club::v1::PRESENCE_LEVEL_RICH); + subscriber->set_whisper_level(club::v1::WHISPER_LEVEL_OPEN); + + // Member is online and active. + subscriber->set_active(true); + + WorldserverService<club::v1::ClubListener>(_session).OnSubscribe(&subscribeNotification, true, true); + + // Notify the client about the changed club state. + club::v1::SubscriberStateChangedNotification subscriberStateChangedNotification; + + subscriberStateChangedNotification.set_club_id(guild->GetId()); + + club::v1::SubscriberStateAssignment* assignment = subscriberStateChangedNotification.add_assignment(); + + assignment->set_allocated_member_id(ClubMembershipService::CreateClubMemberId(player->GetGUID()).release()); + + // Member is online and active. + assignment->set_active(true); + + WorldserverService<club::v1::ClubListener>(_session).OnSubscriberStateChanged(&subscriberStateChangedNotification, true, true); + + return ERROR_OK; +} + +uint32 ClubService::HandleGetMembers(club::v1::GetMembersRequest const* /*request*/, club::v1::GetMembersResponse* response, + std::function<void(ServiceBase*, uint32, google::protobuf::Message const*)>& /*continuation*/) +{ + Player* player = _session->GetPlayer(); + + if (!player) + return ERROR_INTERNAL; + + Guild const* guild = player->GetGuild(); + + if (!guild) + return ERROR_CLUB_NO_CLUB; + + for (auto const& [guid, member] : guild->GetMembers()) + { + club::v1::Member* clubMember = response->add_member(); + + clubMember->set_allocated_id(ClubMembershipService::CreateClubMemberId(guid).release()); + + // Community/Club default roles have slightly different values. + // When communities are implemented those are going to be database fields. + if (member.IsRank(GuildRankId::GuildMaster)) + clubMember->add_role(AsUnderlyingType(ClubRoleIdentifier::Owner)); + else if (guild->HasAnyRankRight(member.GetRankId(), GuildRankRights(GR_RIGHT_OFFCHATLISTEN | GR_RIGHT_OFFCHATSPEAK))) + clubMember->add_role(AsUnderlyingType(ClubRoleIdentifier::Moderator)); + else + clubMember->add_role(AsUnderlyingType(ClubRoleIdentifier::Member)); + + clubMember->set_presence_level(club::v1::PresenceLevel::PRESENCE_LEVEL_RICH); + clubMember->set_whisper_level(club::v1::WhisperLevel::WHISPER_LEVEL_OPEN); + clubMember->set_note(member.GetPublicNote()); + clubMember->set_active(member.IsOnline()); + } + + return ERROR_OK; +} + +uint32 ClubService::HandleGetStreams(club::v1::GetStreamsRequest const* /*request*/, club::v1::GetStreamsResponse* response, + std::function<void(ServiceBase*, uint32, google::protobuf::Message const*)>& /*continuation*/) +{ + Player* player = _session->GetPlayer(); + + if (!player) + return ERROR_INTERNAL; + + Guild const* guild = player->GetGuild(); + + if (!guild) + return ERROR_CLUB_NO_CLUB; + + // General guild channel. + club::v1::Stream* generalGuildChannelStream = response->add_stream(); + + generalGuildChannelStream->set_club_id(guild->GetId()); + generalGuildChannelStream->set_id(AsUnderlyingType(ClubStreamType::Guild)); + + v2::Attribute* generalStreamAttribute = generalGuildChannelStream->add_attribute(); + + generalStreamAttribute->set_name("global_strings_tag"); + generalStreamAttribute->mutable_value()->set_string_value("COMMUNITIES_GUILD_GENERAL_CHANNEL_NAME"); + + generalGuildChannelStream->set_name("Guild"); + + // All roles got access to this channel. + // Club roles are currently guild role + 1. + // With a complete club/community system those will be handled differently. + generalGuildChannelStream->mutable_access()->add_role(AsUnderlyingType(ClubRoleIdentifier::Owner)); + generalGuildChannelStream->mutable_access()->add_role(AsUnderlyingType(ClubRoleIdentifier::Leader)); + generalGuildChannelStream->mutable_access()->add_role(AsUnderlyingType(ClubRoleIdentifier::Moderator)); + generalGuildChannelStream->mutable_access()->add_role(AsUnderlyingType(ClubRoleIdentifier::Member)); + + // No voice support. + generalGuildChannelStream->set_voice_level(club::v1::StreamVoiceLevel::VOICE_LEVEL_DISABLED); + + // Officer guild channel. + club::v1::Stream* officerGuildChannelStream = response->add_stream(); + + officerGuildChannelStream->set_club_id(guild->GetId()); + officerGuildChannelStream->set_id(AsUnderlyingType(ClubStreamType::Officer)); + + v2::Attribute* officerStreamAttribute = officerGuildChannelStream->add_attribute(); + + officerStreamAttribute->set_name("global_strings_tag"); + officerStreamAttribute->mutable_value()->set_string_value("COMMUNITIES_GUILD_OFFICER_CHANNEL_NAME"); + + officerGuildChannelStream->set_name("Officer"); + + // All roles got access to this channel. + // Club roles are currently guild role + 1. + // With a complete club/community system those will be handled differently. + officerGuildChannelStream->mutable_access()->add_role(AsUnderlyingType(ClubRoleIdentifier::Owner)); + officerGuildChannelStream->mutable_access()->add_role(AsUnderlyingType(ClubRoleIdentifier::Leader)); + officerGuildChannelStream->mutable_access()->add_role(AsUnderlyingType(ClubRoleIdentifier::Moderator)); + + // No voice support. + officerGuildChannelStream->set_voice_level(club::v1::StreamVoiceLevel::VOICE_LEVEL_DISABLED); + + // Enable channel view + club::v1::StreamView* generalView = response->add_view(); + + generalView->set_club_id(guild->GetId()); + generalView->set_stream_id(AsUnderlyingType(ClubStreamType::Guild)); + + club::v1::StreamView* officerView = response->add_view(); + + officerView->set_club_id(guild->GetId()); + officerView->set_stream_id(AsUnderlyingType(ClubStreamType::Officer)); + + return ERROR_OK; +} + +uint32 ClubService::HandleSubscribeStream(club::v1::SubscribeStreamRequest const* request, NoData* /*response*/, + std::function<void(ServiceBase*, uint32, google::protobuf::Message const*)>& /*continuation*/) +{ + Player const* player = _session->GetPlayer(); + + if (!player) + return ERROR_INTERNAL; + + Guild const* guild = player->GetGuild(); + + if (!guild) + return ERROR_CLUB_NO_CLUB; + + // Basic sanity check until full communities are implemented. + // 1 - Guild, 2 - Officer chat stream. + if (request->stream_id().empty() || (request->stream_id().Get(0) != AsUnderlyingType(ClubStreamType::Guild) && request->stream_id().Get(0) != AsUnderlyingType(ClubStreamType::Officer))) + return ERROR_CLUB_STREAM_NO_STREAM; + + return ERROR_OK; +} + +uint32 ClubService::HandleUnsubscribeStream(club::v1::UnsubscribeStreamRequest const* /*request*/, NoData* /*response*/, + std::function<void(ServiceBase*, uint32, google::protobuf::Message const*)>& /*continuation*/) +{ + // We just have to signal the client that the unsubscribe request came through. + return ERROR_OK; +} + +uint32 ClubService::HandleSetStreamFocus(club::v1::SetStreamFocusRequest const* /*request*/, NoData* /*response*/, + std::function<void(ServiceBase*, uint32, google::protobuf::Message const*)>& /*continuation*/) +{ + Player const* player = _session->GetPlayer(); + + if (!player) + return ERROR_INTERNAL; + + Guild const* guild = player->GetGuild(); + + if (!guild) + return ERROR_CLUB_NOT_MEMBER; + + return ERROR_OK; +} + +uint32 ClubService::HandleAdvanceStreamViewTime(club::v1::AdvanceStreamViewTimeRequest const* /*request*/, NoData* /*response*/, + std::function<void(ServiceBase*, uint32, google::protobuf::Message const*)>& /*continuation*/) +{ + Player const* player = _session->GetPlayer(); + + if (!player) + return ERROR_INTERNAL; + + Guild const* guild = player->GetGuild(); + + if (!guild) + return ERROR_CLUB_NOT_MEMBER; + + return ERROR_OK; +} + +uint32 ClubService::HandleCreateMessage(club::v1::CreateMessageRequest const* request, club::v1::CreateMessageResponse* response, + std::function<void(ServiceBase*, uint32, google::protobuf::Message const*)>& continuation) +{ + // Basic sanity check until full communities are implemented. + // 1 - Guild, 2 - Officer chat stream. + if (request->stream_id() != AsUnderlyingType(ClubStreamType::Guild) && request->stream_id() != AsUnderlyingType(ClubStreamType::Officer)) + return ERROR_CLUB_STREAM_NO_STREAM; + + // Just some sanity checks. We do not care about the requested stream for now since we only have two. + Player const* player = _session->GetPlayer(); + + if (!player) + return ERROR_INTERNAL; + + Guild const* guild = player->GetGuild(); + + if (!guild) + return ERROR_CLUB_NO_CLUB; + + GuildRankRights requiredRights = { }; + ChatMessageResult result = { }; + + switch (ClubStreamType(request->stream_id())) + { + case ClubStreamType::Guild: + requiredRights = GR_RIGHT_GCHATLISTEN; + result = _session->HandleChatMessage(CHAT_MSG_GUILD, LANG_UNIVERSAL, request->options().content()); + break; + case ClubStreamType::Officer: + requiredRights = GR_RIGHT_OFFCHATLISTEN; + result = _session->HandleChatMessage(CHAT_MSG_OFFICER, LANG_UNIVERSAL, request->options().content()); + break; + default: + return ERROR_CLUB_STREAM_NO_STREAM; + } + + if (result == ChatMessageResult::Ok) + { + std::chrono::microseconds messageTime = std::chrono::duration_cast<std::chrono::microseconds>(GameTime::GetSystemTime().time_since_epoch()); + + FillStreamMessage(response->mutable_message(), request->options().content(), messageTime, player->GetGUID()); + + club::v1::StreamMessageAddedNotification messageAddedNotification; + messageAddedNotification.set_allocated_agent_id(ClubMembershipService::CreateClubMemberId(player->GetGUID()).release()); + messageAddedNotification.set_club_id(guild->GetId()); + messageAddedNotification.set_stream_id(request->stream_id()); + FillStreamMessage(messageAddedNotification.mutable_message(), request->options().content(), messageTime, player->GetGUID()); + + guild->BroadcastWorker([&](Player const* receiver) + { + Guild::Member const* receiverMember = guild->GetMember(receiver->GetGUID()); + if (!guild->HasAnyRankRight(receiverMember->GetRankId(), requiredRights)) + return; + + if (receiver->GetSocial()->HasIgnore(player->GetGUID(), _session->GetAccountGUID())) + return; + + WorldserverService<club::v1::ClubListener>(receiver->GetSession()).OnStreamMessageAdded(&messageAddedNotification, true, true); + }, player); + + return ERROR_OK; + } + + // If the message is empty there should never be a response to message request. + continuation = nullptr; + + return ERROR_CLUB_STREAM_NO_SUCH_MESSAGE; +} + +std::unique_ptr<club::v1::UniqueClubType> ClubService::CreateGuildClubType() +{ + std::unique_ptr<club::v1::UniqueClubType> type = std::make_unique<club::v1::UniqueClubType>(); + type->set_program(5730135); + type->set_name("guild"); + return type; +} + +void ClubService::FillStreamMessage(club::v1::StreamMessage* message, std::string_view msg, std::chrono::microseconds messageTime, ObjectGuid author) +{ + message->mutable_id()->set_epoch(messageTime.count()); + message->mutable_id()->set_position(0); + + message->mutable_author()->set_allocated_id(ClubMembershipService::CreateClubMemberId(author).release()); + + club::v1::ContentChain* contentChain = message->add_content_chain(); + + contentChain->set_content(msg.data(), msg.size()); + contentChain->set_edit_time(messageTime.count()); +} +} diff --git a/src/server/game/Services/ClubService.h b/src/server/game/Services/ClubService.h new file mode 100644 index 00000000000..8a7072bc5d0 --- /dev/null +++ b/src/server/game/Services/ClubService.h @@ -0,0 +1,51 @@ +/* + * 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 ClubService_h__ +#define ClubService_h__ + +#include "WorldserverService.h" +#include "club_service.pb.h" + +namespace Battlenet::Services +{ +class ClubService : public WorldserverService<club::v1::ClubService> +{ + typedef WorldserverService<club::v1::ClubService> BaseService; + +public: + + ClubService(WorldSession* session); + + uint32 HandleGetClubType(club::v1::GetClubTypeRequest const* request, club::v1::GetClubTypeResponse* response, std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)>& continuation) override; + uint32 HandleSubscribe(club::v1::SubscribeRequest const* request, NoData* response, std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)>& continuation) override; + uint32 HandleGetMembers(club::v1::GetMembersRequest const* request, club::v1::GetMembersResponse* response, std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)>& continuation) override; + uint32 HandleGetStreams(club::v1::GetStreamsRequest const* request, club::v1::GetStreamsResponse* response, std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)>& continuation) override; + uint32 HandleSubscribeStream(club::v1::SubscribeStreamRequest const* request, NoData* response, std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)>& continuation) override; + uint32 HandleUnsubscribeStream(club::v1::UnsubscribeStreamRequest const* request, NoData* response, std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)>& continuation) override; + uint32 HandleSetStreamFocus(club::v1::SetStreamFocusRequest const* request, NoData* response, std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)>& continuation) override; + uint32 HandleAdvanceStreamViewTime(club::v1::AdvanceStreamViewTimeRequest const* request, NoData* response, std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)>& continuation) override; + uint32 HandleCreateMessage(club::v1::CreateMessageRequest const* request, club::v1::CreateMessageResponse* response, std::function<void(ServiceBase*, uint32, ::google::protobuf::Message const*)>& continuation) override; + + static std::unique_ptr<club::v1::UniqueClubType> CreateGuildClubType(); + +private: + static void FillStreamMessage(club::v1::StreamMessage* message, std::string_view msg, std::chrono::microseconds messageTime, ObjectGuid author); +}; +} + +#endif // ClubService_h__ diff --git a/src/server/game/Services/ClubUtils.cpp b/src/server/game/Services/ClubUtils.cpp new file mode 100644 index 00000000000..7147b2367b1 --- /dev/null +++ b/src/server/game/Services/ClubUtils.cpp @@ -0,0 +1,25 @@ +/* + * 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 "ClubUtils.h" +#include "Realm.h" +#include "World.h" + +uint64 Battlenet::Services::Clubs::CreateClubMemberId(ObjectGuid guid) +{ + return guid.GetCounter() | (uint64(realm.Id.Realm & 0xFFF) << 48); +} diff --git a/src/server/game/Services/ClubUtils.h b/src/server/game/Services/ClubUtils.h new file mode 100644 index 00000000000..719c8295867 --- /dev/null +++ b/src/server/game/Services/ClubUtils.h @@ -0,0 +1,28 @@ +/* + * 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_CLUB_UTILS_H +#define TRINITYCORE_CLUB_UTILS_H + +#include "ObjectGuid.h" + +namespace Battlenet::Services::Clubs +{ +uint64 CreateClubMemberId(ObjectGuid guid); +} + +#endif // TRINITYCORE_CLUB_UTILS_H diff --git a/src/server/game/Services/WorldserverGameUtilitiesService.h b/src/server/game/Services/WorldserverGameUtilitiesService.h index 46e729eae22..2d7832686b3 100644 --- a/src/server/game/Services/WorldserverGameUtilitiesService.h +++ b/src/server/game/Services/WorldserverGameUtilitiesService.h @@ -23,8 +23,6 @@ namespace Battlenet { - class Session; - namespace Services { class GameUtilitiesService : public WorldserverService<game_utilities::v1::GameUtilitiesService> diff --git a/src/server/game/Services/WorldserverServiceDispatcher.cpp b/src/server/game/Services/WorldserverServiceDispatcher.cpp index 77177139790..62e25e6e326 100644 --- a/src/server/game/Services/WorldserverServiceDispatcher.cpp +++ b/src/server/game/Services/WorldserverServiceDispatcher.cpp @@ -21,8 +21,8 @@ Battlenet::WorldserverServiceDispatcher::WorldserverServiceDispatcher() { AddService<WorldserverService<account::v1::AccountService>>(); AddService<WorldserverService<authentication::v1::AuthenticationService>>(); - AddService<WorldserverService<club::v1::membership::ClubMembershipService>>(); - AddService<WorldserverService<club::v1::ClubService>>(); + AddService<Services::ClubMembershipService>(); + AddService<Services::ClubService>(); AddService<WorldserverService<connection::v1::ConnectionService>>(); AddService<WorldserverService<friends::v1::FriendsService>>(); AddService<Services::GameUtilitiesService>(); diff --git a/src/server/game/Services/WorldserverServiceDispatcher.h b/src/server/game/Services/WorldserverServiceDispatcher.h index c40d2c883ab..70e76aacc3f 100644 --- a/src/server/game/Services/WorldserverServiceDispatcher.h +++ b/src/server/game/Services/WorldserverServiceDispatcher.h @@ -26,8 +26,8 @@ #include "challenge_service.pb.h" #include "club_listener.pb.h" #include "club_membership_listener.pb.h" -#include "club_membership_service.pb.h" -#include "club_service.pb.h" +#include "ClubMembershipService.h" +#include "ClubService.h" #include "connection_service.pb.h" #include "friends_service.pb.h" #include "WorldserverGameUtilitiesService.h" diff --git a/src/server/proto/BattlenetRpcErrorCodes.h b/src/server/proto/BattlenetRpcErrorCodes.h index 1f7e0b56ebf..5b25bfebb4b 100644 --- a/src/server/proto/BattlenetRpcErrorCodes.h +++ b/src/server/proto/BattlenetRpcErrorCodes.h @@ -30,44 +30,28 @@ enum BattlenetRpcErrorCode : uint32 ERROR_NOT_STARTED = 0x00000005, ERROR_IN_PROGRESS = 0x00000006, ERROR_INVALID_ARGS = 0x00000007, - ERROR_INVALID_SUBSCRIBER = 0x00000008, - ERROR_WAITING_FOR_DEPENDENCY = 0x00000009, ERROR_NO_AUTH = 0x0000000A, ERROR_PARENTAL_CONTROL_RESTRICTION = 0x0000000B, ERROR_NO_GAME_ACCOUNT = 0x0000000C, ERROR_NOT_IMPLEMENTED = 0x0000000D, - ERROR_OBJECT_REMOVED = 0x0000000E, - ERROR_INVALID_ENTITY_ID = 0x0000000F, - ERROR_INVALID_ENTITY_ACCOUNT_ID = 0x00000010, - ERROR_INVALID_ENTITY_GAME_ACCOUNT_ID = 0x00000011, ERROR_INVALID_AGENT_ID = 0x00000013, ERROR_INVALID_TARGET_ID = 0x00000014, - ERROR_MODULE_NOT_LOADED = 0x00000015, - ERROR_MODULE_NO_ENTRY_POINT = 0x00000016, - ERROR_MODULE_SIGNATURE_INCORRECT = 0x00000017, - ERROR_MODULE_CREATE_FAILED = 0x00000018, ERROR_NO_PROGRAM = 0x00000019, ERROR_API_NOT_READY = 0x0000001B, ERROR_BAD_VERSION = 0x0000001C, ERROR_ATTRIBUTE_TOO_MANY_ATTRIBUTES_SET = 0x0000001D, ERROR_ATTRIBUTE_MAX_SIZE_EXCEEDED = 0x0000001E, ERROR_ATTRIBUTE_QUOTA_EXCEEDED = 0x0000001F, - ERROR_SERVER_POOL_SERVER_DISAPPEARED = 0x00000020, ERROR_SERVER_IS_PRIVATE = 0x00000021, ERROR_DISABLED = 0x00000022, - ERROR_MODULE_NOT_FOUND = 0x00000024, ERROR_SERVER_BUSY = 0x00000025, ERROR_NO_BATTLETAG = 0x00000026, - ERROR_INCOMPLETE_PROFANITY_FILTERS = 0x00000027, ERROR_INVALID_REGION = 0x00000028, ERROR_EXISTS_ALREADY = 0x00000029, - ERROR_INVALID_SERVER_THUMBPRINT = 0x0000002A, ERROR_PHONE_LOCK = 0x0000002B, ERROR_SQUELCHED = 0x0000002C, ERROR_TARGET_OFFLINE = 0x0000002D, ERROR_BAD_SERVER = 0x0000002E, - ERROR_NO_COOKIE = 0x0000002F, - ERROR_EXPIRED_COOKIE = 0x00000030, ERROR_TOKEN_NOT_FOUND = 0x00000031, ERROR_GAME_ACCOUNT_NO_TIME = 0x00000032, ERROR_GAME_ACCOUNT_NO_PLAN = 0x00000033, @@ -77,13 +61,17 @@ enum BattlenetRpcErrorCode : uint32 ERROR_GAME_ACCOUNT_CANCELLED = 0x00000037, ERROR_GAME_ACCOUNT_CREATION_DISABLED = 0x00000038, ERROR_GAME_ACCOUNT_LOCKED = 0x00000039, - + ERROR_GAME_ACCOUNT_PHONE_LOCK = 0x0000003A, + ERROR_GAME_ACCOUNT_BILLING_LOCK = 0x0000003B, ERROR_SESSION_DUPLICATE = 0x0000003C, ERROR_SESSION_DISCONNECTED = 0x0000003D, ERROR_SESSION_DATA_CHANGED = 0x0000003E, ERROR_SESSION_UPDATE_FAILED = 0x0000003F, ERROR_SESSION_NOT_FOUND = 0x00000040, - + ERROR_SESSION_FREE_PLAY_NOT_SUPPORTED = 0x00000041, + ERROR_SESSION_SUBSCRIPTION_ADDED = 0x00000042, + ERROR_SESSION_CONSUMPTION_TIME_ADDED = 0x00000043, + ERROR_SESSION_TOKEN_NOT_FOUND = 0x00000044, ERROR_ADMIN_KICK = 0x00000046, ERROR_UNPLANNED_MAINTENANCE = 0x00000047, ERROR_PLANNED_MAINTENANCE = 0x00000048, @@ -99,42 +87,29 @@ enum BattlenetRpcErrorCode : uint32 ERROR_LOCALE_RESTRICTED_KO = 0x00000053, ERROR_LOCALE_RESTRICTED_TW = 0x00000054, ERROR_LOCALE_RESTRICTED = 0x00000055, - ERROR_ACCOUNT_NEEDS_MAINTENANCE = 0x00000056, - ERROR_MODULE_API_ERROR = 0x00000057, - ERROR_MODULE_BAD_CACHE_HANDLE = 0x00000058, - ERROR_MODULE_ALREADY_LOADED = 0x00000059, - ERROR_NETWORK_BLACKLISTED = 0x0000005A, + ERROR_NETWORK_BLOCKLISTED = 0x0000005A, ERROR_EVENT_PROCESSOR_SLOW = 0x0000005B, ERROR_SERVER_SHUTTING_DOWN = 0x0000005C, ERROR_NETWORK_NOT_PRIVILEGED = 0x0000005D, ERROR_TOO_MANY_OUTSTANDING_REQUESTS = 0x0000005E, - ERROR_NO_ACCOUNT_REGISTERED = 0x0000005F, ERROR_BATTLENET_ACCOUNT_BANNED = 0x00000060, - - ERROR_OK_DEPRECATED = 0x00000064, ERROR_SERVER_IN_MODE_ZOMBIE = 0x00000065, + ERROR_AGENT_IS_BLOCKING_TARGET = 0x00000066, + ERROR_TARGET_IS_BLOCKING_AGENT = 0x00000067, + ERROR_FEATURE_UNAVAILABLE = 0x00000068, + ERROR_BROKEN_PROMISE = 0x00000069, + ERROR_UNINITIALIZED_EXPECTED = 0x0000006A, + ERROR_NO_SSL_CONNECTION = 0x0000006B, + ERROR_SERVICE_NOT_READY = 0x0000006E, - ERROR_LOGON_MODULE_REQUIRED = 0x000001F4, - ERROR_LOGON_MODULE_NOT_CONFIGURED = 0x000001F5, - ERROR_LOGON_MODULE_TIMEOUT = 0x000001F6, - ERROR_LOGON_AGREEMENT_REQUIRED = 0x000001FE, - ERROR_LOGON_AGREEMENT_NOT_CONFIGURED = 0x000001FF, - - ERROR_LOGON_INVALID_SERVER_PROOF = 0x00000208, ERROR_LOGON_WEB_VERIFY_TIMEOUT = 0x00000209, ERROR_LOGON_INVALID_AUTH_TOKEN = 0x0000020A, - - ERROR_CHALLENGE_SMS_TOO_SOON = 0x00000258, - ERROR_CHALLENGE_SMS_THROTTLED = 0x00000259, - ERROR_CHALLENGE_SMS_TEMP_OUTAGE = 0x0000025A, - ERROR_CHALLENGE_NO_CHALLENGE = 0x0000025B, - ERROR_CHALLENGE_NOT_PICKED = 0x0000025C, - ERROR_CHALLENGE_ALREADY_PICKED = 0x0000025D, - ERROR_CHALLENGE_IN_PROGRESS = 0x0000025E, + ERROR_LOGON_TASSADAR_REQUEST_FAILED = 0x0000020B, ERROR_CONFIG_FORMAT_INVALID = 0x000002BC, ERROR_CONFIG_NOT_FOUND = 0x000002BD, ERROR_CONFIG_RETRIEVE_FAILED = 0x000002BE, + ERROR_CONFIG_DUMP_FAILED = 0x000002BF, ERROR_NETWORK_MODULE_BUSY = 0x000003E8, ERROR_NETWORK_MODULE_CANT_RESOLVE_ADDRESS = 0x000003E9, @@ -153,12 +128,10 @@ enum BattlenetRpcErrorCode : uint32 ERROR_NETWORK_MODULE_NO_SSL_COMMON_NAME_FOR_CERTIFICATE = 0x000003F6, ERROR_NETWORK_MODULE_SSL_COMMON_NAME_DOES_NOT_MATCH_REMOTE_ENDPOINT = 0x000003F7, ERROR_NETWORK_MODULE_SOCKET_CLOSED = 0x000003F8, - ERROR_NETWORK_MODULE_SSL_PEER_IS_NOT_REGISTERED_IN_CERTBUNDLE = 0x000003F9, - ERROR_NETWORK_MODULE_SSL_INITIALIZE_LOW_FIRST = 0x000003FA, - ERROR_NETWORK_MODULE_SSL_CERT_BUNDLE_READ_ERROR = 0x000003FB, - ERROR_NETWORK_MODULE_NO_CERT_BUNDLE = 0x000003FC, - ERROR_NETWORK_MODULE_FAILED_TO_DOWNLOAD_CERT_BUNDLE = 0x000003FD, ERROR_NETWORK_MODULE_NOT_READY_TO_READ = 0x000003FE, + ERROR_NETWORK_MODULE_SSL_CERT_CHAIN_VALIDATION_FAILED = 0x000003FF, + ERROR_NETWORK_MODULE_NETWORK_DOWN = 0x00000401, + ERROR_NETWORK_MODULE_SSL_INITIALIZATION_FAILED = 0x00000402, ERROR_NETWORK_MODULE_OPENSSL_X509_OK = 0x000004B0, ERROR_NETWORK_MODULE_OPENSSL_X509_UNABLE_TO_GET_ISSUER_CERT = 0x000004B1, @@ -200,6 +173,7 @@ enum BattlenetRpcErrorCode : uint32 ERROR_NETWORK_MODULE_SCHANNEL_CANNOT_FIND_INTERFACE = 0x00000517, ERROR_NETWORK_MODULE_SCHANNEL_INIT_FAIL = 0x00000518, ERROR_NETWORK_MODULE_SCHANNEL_FUNCTION_CALL_FAIL = 0x00000519, + ERROR_NETWORK_MODULE_SCHANNEL_HANDSHAKE_FAILURE = 0x0000051A, ERROR_NETWORK_MODULE_SCHANNEL_X509_UNABLE_TO_GET_ISSUER_CERT = 0x00000546, ERROR_NETWORK_MODULE_SCHANNEL_X509_TIME_INVALID = 0x00000547, ERROR_NETWORK_MODULE_SCHANNEL_X509_SIGNATURE_INVALID = 0x00000548, @@ -207,24 +181,31 @@ enum BattlenetRpcErrorCode : uint32 ERROR_NETWORK_MODULE_SCHANNEL_X509_SELF_SIGNED_LEAF_CERTIFICATE = 0x0000054A, ERROR_NETWORK_MODULE_SCHANNEL_X509_UNHANDLED_ERROR = 0x0000054B, ERROR_NETWORK_MODULE_SCHANNEL_X509_SELF_SIGNED_CERT_IN_CHAIN = 0x0000054C, - ERROR_WEBSOCKET_HANDSHAKE = 0x00000578, - ERROR_NETWORK_MODULE_DURANGO_UNKNOWN = 0x000005DC, ERROR_NETWORK_MODULE_DURANGO_MALFORMED_HOST_NAME = 0x000005DD, ERROR_NETWORK_MODULE_DURANGO_INVALID_CONNECTION_RESPONSE = 0x000005DE, ERROR_NETWORK_MODULE_DURANGO_INVALID_CA_CERT = 0x000005DF, + ERROR_NETWORK_MODULE_DARWINSSL_FUNCTION_CALL_FAIL = 0x00000640, + ERROR_NETWORK_MODULE_DARWINSSL_X509_NEVER_TRUST = 0x00000672, + ERROR_NETWORK_MODULE_DARWINSSL_X509_UNKNOWN_ERROR = 0x00000676, + ERROR_NETWORK_MODULE_SCE_SSL_CONTEXT_ALLOCATE_FAILED = 0x000006A4, + ERROR_NETWORK_MODULE_SCE_SSL_CONNECTION_ALLOCATE_FAILED = 0x000006A5, + ERROR_NETWORK_MODULE_SCE_SSL_SET_VERIFY_OPTION_FAILED = 0x000006A6, + ERROR_NETWORK_MODULE_SCE_SSL_HANDSHAKE_FAILED = 0x000006A7, + + ERROR_SDK_MESSAGE_HANDLER_NOT_FOUND = 0x0000076C, + ERROR_SDK_TASSADAR_CLIENT_INVALID_INPUT = 0x00000776, + ERROR_SDK_TASSADAR_SERVER_ERROR = 0x00000777, + ERROR_SDK_TASSADAR_SERVER_MAINTENANCE = 0x00000778, ERROR_RPC_WRITE_FAILED = 0x00000BB8, - ERROR_RPC_SERVICE_NOT_BOUND = 0x00000BB9, ERROR_RPC_TOO_MANY_REQUESTS = 0x00000BBA, ERROR_RPC_PEER_UNKNOWN = 0x00000BBB, ERROR_RPC_PEER_UNAVAILABLE = 0x00000BBC, ERROR_RPC_PEER_DISCONNECTED = 0x00000BBD, ERROR_RPC_REQUEST_TIMED_OUT = 0x00000BBE, - ERROR_RPC_CONNECTION_TIMED_OUT = 0x00000BBF, ERROR_RPC_MALFORMED_RESPONSE = 0x00000BC0, - ERROR_RPC_ACCESS_DENIED = 0x00000BC1, ERROR_RPC_INVALID_SERVICE = 0x00000BC2, ERROR_RPC_INVALID_METHOD = 0x00000BC3, ERROR_RPC_INVALID_OBJECT = 0x00000BC4, @@ -234,30 +215,25 @@ enum BattlenetRpcErrorCode : uint32 ERROR_RPC_SERVER_ERROR = 0x00000BC8, ERROR_RPC_SHUTDOWN = 0x00000BC9, ERROR_RPC_DISCONNECT = 0x00000BCA, - ERROR_RPC_DISCONNECT_IDLE = 0x00000BCB, ERROR_RPC_PROTOCOL_ERROR = 0x00000BCC, ERROR_RPC_NOT_READY = 0x00000BCD, ERROR_RPC_FORWARD_FAILED = 0x00000BCE, - ERROR_RPC_ENCRYPTION_FAILED = 0x00000BCF, ERROR_RPC_INVALID_ADDRESS = 0x00000BD0, ERROR_RPC_METHOD_DISABLED = 0x00000BD1, ERROR_RPC_SHARD_NOT_FOUND = 0x00000BD2, ERROR_RPC_INVALID_CONNECTION_ID = 0x00000BD3, ERROR_RPC_NOT_CONNECTED = 0x00000BD4, ERROR_RPC_INVALID_CONNECTION_STATE = 0x00000BD5, - ERROR_RPC_SERVICE_ALREADY_REGISTERED = 0x00000BD6, - - ERROR_PRESENCE_INVALID_FIELD_ID = 0x00000FA0, - ERROR_PRESENCE_NO_VALID_SUBSCRIBERS = 0x00000FA1, - ERROR_PRESENCE_ALREADY_SUBSCRIBED = 0x00000FA2, - ERROR_PRESENCE_CONSUMER_NOT_FOUND = 0x00000FA3, - ERROR_PRESENCE_CONSUMER_IS_NULL = 0x00000FA4, - ERROR_PRESENCE_TEMPORARY_OUTAGE = 0x00000FA5, + ERROR_RPC_CONNECTION_UNREACHABLE = 0x00000BD7, + ERROR_RPC_NO_BUFFER_SPACE = 0x00000BD8, + ERROR_RPC_HTTP_PROBE = 0x00000BD9, + ERROR_RPC_CLIENT_ID_REQUIRED = 0x00000BDA, + ERROR_RPC_CONNECTION_REPLACED = 0x00000BDB, + ERROR_RPC_INVALID_ROUTE = 0x00000BDC, + ERROR_PRESENCE_TOO_MANY_SUBSCRIPTIONS = 0x00000FA6, - ERROR_PRESENCE_SUBSCRIPTION_CANCELLED = 0x00000FA7, - ERROR_PRESENCE_RICH_PRESENCE_PARSE_ERROR = 0x00000FA8, - ERROR_PRESENCE_RICH_PRESENCE_XML_ERROR = 0x00000FA9, - ERROR_PRESENCE_RICH_PRESENCE_LOAD_ERROR = 0x00000FAA, + ERROR_PRESENCE_NO_RECORD = 0x00000FAB, + ERROR_PRESENCE_NO_CHANGE = 0x00000FAC, ERROR_FRIENDS_TOO_MANY_SENT_INVITATIONS = 0x00001389, ERROR_FRIENDS_TOO_MANY_RECEIVED_INVITATIONS = 0x0000138A, @@ -265,7 +241,6 @@ enum BattlenetRpcErrorCode : uint32 ERROR_FRIENDS_FRIENDSHIP_DOES_NOT_EXIST = 0x0000138C, ERROR_FRIENDS_INVITATION_ALREADY_EXISTS = 0x0000138D, ERROR_FRIENDS_INVALID_INVITATION = 0x0000138E, - ERROR_FRIENDS_ALREADY_SUBSCRIBED = 0x0000138F, ERROR_FRIENDS_ACCOUNT_BLOCKED = 0x00001391, ERROR_FRIENDS_NOT_SUBSCRIBED = 0x00001392, ERROR_FRIENDS_INVALID_ROLE_ID = 0x00001393, @@ -274,11 +249,20 @@ enum BattlenetRpcErrorCode : uint32 ERROR_FRIENDS_UPDATE_FRIEND_STATE_FAILED = 0x00001396, ERROR_FRIENDS_INVITEE_AT_MAX_FRIENDS = 0x00001397, ERROR_FRIENDS_INVITER_AT_MAX_FRIENDS = 0x00001398, + ERROR_FRIENDS_INVITER_IS_BLOCKED_BY_INVITEE = 0x00001399, + ERROR_FRIENDS_RECEIVED_INVITATION_UNDELIVERABLE = 0x0000139A, + ERROR_FRIENDS_MUTED = 0x0000139B, + ERROR_FRIENDS_RECEIVED_INVITATION_IGNORED = 0x0000139C, + ERROR_FRIENDS_TRANSACTION_ALREADY_EXISTS = 0x0000139D, + ERROR_FRIENDS_MERGED_FRIENDS_ABOVE_LIMIT = 0x0000139E, ERROR_PLATFORM_STORAGE_FILE_WRITE_DENIED = 0x00001770, ERROR_WHISPER_UNDELIVERABLE = 0x00001B58, ERROR_WHISPER_MAX_SIZE_EXCEEDED = 0x00001B59, + ERROR_WHISPER_ALREADY_REGISTERED = 0x00001B5A, + ERROR_WHISPER_DROPPED = 0x00001B5B, + ERROR_WHISPER_QUOTA_EXCEEDED = 0x00001B5C, ERROR_USER_MANAGER_ALREADY_BLOCKED = 0x00001F40, ERROR_USER_MANAGER_NOT_BLOCKED = 0x00001F41, @@ -292,73 +276,88 @@ enum BattlenetRpcErrorCode : uint32 ERROR_USER_MANAGER_UNBLOCK_ENTITY_FAILED = 0x00001F51, ERROR_USER_MANAGER_CANNOT_BLOCK_FRIEND = 0x00001F53, - ERROR_SOCIAL_NETWORK_DB_EXCEPTION = 0x00002328, - ERROR_SOCIAL_NETWORK_DENIAL_FROM_PROVIDER = 0x00002329, - ERROR_SOCIAL_NETWORK_INVALID_SNS_ID = 0x0000232A, - ERROR_SOCIAL_NETWORK_CANT_SEND_TO_PROVIDER = 0x0000232B, - ERROR_SOCIAL_NETWORK_EX_COMM_FAILED = 0x0000232C, - ERROR_SOCIAL_NETWORK_DISABLED = 0x0000232D, - ERROR_SOCIAL_NETWORK_MISSING_REQUEST_PARAM = 0x0000232E, - ERROR_SOCIAL_NETWORK_UNSUPPORTED_OAUTH_VERSION = 0x0000232F, + ERROR_SOCIAL_NETWORK_OAUTH_EXCEPTION = 0x00002328, + ERROR_SOCIAL_NETWORK_INVALID_SNS_ID = 0x00002329, + ERROR_SOCIAL_NETWORK_CANT_SEND_TO_PROVIDER = 0x0000232A, + ERROR_SOCIAL_NETWORK_DISABLED = 0x0000232B, + ERROR_SOCIAL_NETWORK_MISSING_REQUEST_PARAM = 0x0000232C, + ERROR_SOCIAL_NETWORK_NO_ACCOUNT_DATA = 0x0000232D, + ERROR_SOCIAL_NETWORK_NO_TOKEN = 0x0000232E, + ERROR_SOCIAL_NETWORK_MISSING_DATA_FROM_PROVIDER = 0x0000232F, + ERROR_SOCIAL_NETWORK_RESPONSE_NOT_PARSABLE = 0x00002330, + ERROR_SOCIAL_NETWORK_TOKEN_PERMISSION_DENIED = 0x00002331, + ERROR_SOCIAL_NETWORK_DENIAL_FROM_PROVIDER = 0x00002332, ERROR_CHANNEL_FULL = 0x00002710, ERROR_CHANNEL_NO_CHANNEL = 0x00002711, ERROR_CHANNEL_NOT_MEMBER = 0x00002712, ERROR_CHANNEL_ALREADY_MEMBER = 0x00002713, ERROR_CHANNEL_NO_SUCH_MEMBER = 0x00002714, - ERROR_CHANNEL_INVALID_CHANNEL_ID = 0x00002716, ERROR_CHANNEL_NO_SUCH_INVITATION = 0x00002718, ERROR_CHANNEL_TOO_MANY_INVITATIONS = 0x00002719, ERROR_CHANNEL_INVITATION_ALREADY_EXISTS = 0x0000271A, - ERROR_CHANNEL_INVALID_CHANNEL_SIZE = 0x0000271B, ERROR_CHANNEL_INVALID_ROLE_ID = 0x0000271C, ERROR_CHANNEL_ROLE_NOT_ASSIGNABLE = 0x0000271D, ERROR_CHANNEL_INSUFFICIENT_PRIVILEGES = 0x0000271E, ERROR_CHANNEL_INSUFFICIENT_PRIVACY_LEVEL = 0x0000271F, ERROR_CHANNEL_INVALID_PRIVACY_LEVEL = 0x00002720, ERROR_CHANNEL_TOO_MANY_CHANNELS_JOINED = 0x00002721, - ERROR_CHANNEL_INVITATION_ALREADY_SUBSCRIBED = 0x00002722, ERROR_CHANNEL_INVALID_CHANNEL_DELEGATE = 0x00002723, ERROR_CHANNEL_SLOT_ALREADY_RESERVED = 0x00002724, - ERROR_CHANNEL_SLOT_NOT_RESERVED = 0x00002725, ERROR_CHANNEL_NO_RESERVED_SLOTS_AVAILABLE = 0x00002726, ERROR_CHANNEL_INVALID_ROLE_SET = 0x00002727, - ERROR_CHANNEL_REQUIRE_FRIEND_VALIDATION = 0x00002728, - ERROR_CHANNEL_MEMBER_OFFLINE = 0x00002729, ERROR_CHANNEL_RECEIVED_TOO_MANY_INVITATIONS = 0x0000272A, ERROR_CHANNEL_INVITATION_INVALID_GAME_ACCOUNT_SELECTED = 0x0000272B, - ERROR_CHANNEL_UNREACHABLE = 0x0000272C, ERROR_CHANNEL_INVITATION_NOT_SUBSCRIBED = 0x0000272D, - ERROR_CHANNEL_INVALID_MESSAGE_SIZE = 0x0000272E, - ERROR_CHANNEL_MAX_MESSAGE_SIZE_EXCEEDED = 0x0000272F, - ERROR_CHANNEL_CONFIG_NOT_FOUND = 0x00002730, ERROR_CHANNEL_INVALID_CHANNEL_TYPE = 0x00002731, - - ERROR_LOCAL_STORAGE_FILE_OPEN_ERROR = 0x00002AF8, - ERROR_LOCAL_STORAGE_FILE_CREATE_ERROR = 0x00002AF9, - ERROR_LOCAL_STORAGE_FILE_READ_ERROR = 0x00002AFA, - ERROR_LOCAL_STORAGE_FILE_WRITE_ERROR = 0x00002AFB, - ERROR_LOCAL_STORAGE_FILE_DELETE_ERROR = 0x00002AFC, - ERROR_LOCAL_STORAGE_FILE_COPY_ERROR = 0x00002AFD, - ERROR_LOCAL_STORAGE_FILE_DECOMPRESS_ERROR = 0x00002AFE, - ERROR_LOCAL_STORAGE_FILE_HASH_MISMATCH = 0x00002AFF, - ERROR_LOCAL_STORAGE_FILE_USAGE_MISMATCH = 0x00002B00, - ERROR_LOCAL_STORAGE_DATABASE_INIT_ERROR = 0x00002B01, - ERROR_LOCAL_STORAGE_DATABASE_NEEDS_REBUILD = 0x00002B02, - ERROR_LOCAL_STORAGE_DATABASE_INSERT_ERROR = 0x00002B03, - ERROR_LOCAL_STORAGE_DATABASE_LOOKUP_ERROR = 0x00002B04, - ERROR_LOCAL_STORAGE_DATABASE_UPDATE_ERROR = 0x00002B05, - ERROR_LOCAL_STORAGE_DATABASE_DELETE_ERROR = 0x00002B06, - ERROR_LOCAL_STORAGE_DATABASE_SHRINK_ERROR = 0x00002B07, - ERROR_LOCAL_STORAGE_CACHE_CRAWL_ERROR = 0x00002B08, - ERROR_LOCAL_STORAGE_DATABASE_INDEX_TRIGGER_ERROR = 0x00002B09, - ERROR_LOCAL_STORAGE_DATABASE_REBUILD_IN_PROGRESS = 0x00002B0A, - ERROR_LOCAL_STORAGE_OK_BUT_NOT_IN_CACHE = 0x00002B0B, - ERROR_LOCAL_STORAGE_DATABASE_REBUILD_INTERRUPTED = 0x00002B0D, - ERROR_LOCAL_STORAGE_DATABASE_NOT_INITIALIZED = 0x00002B0E, - ERROR_LOCAL_STORAGE_DIRECTORY_CREATE_ERROR = 0x00002B0F, - ERROR_LOCAL_STORAGE_FILEKEY_NOT_FOUND = 0x00002B10, - ERROR_LOCAL_STORAGE_NOT_AVAILABLE_ON_SERVER = 0x00002B11, + ERROR_CHANNEL_INVALID_INDEX = 0x00002732, + ERROR_CHANNEL_MEMBERSHIP_NOT_SUBSCRIBED = 0x00002733, + ERROR_CHANNEL_ALREADY_SUBSCRIBED = 0x00002734, + + ERROR_CLUB_FULL = 0x00002AF8, + ERROR_CLUB_NO_CLUB = 0x00002AF9, + ERROR_CLUB_NOT_MEMBER = 0x00002AFA, + ERROR_CLUB_ALREADY_MEMBER = 0x00002AFB, + ERROR_CLUB_NO_SUCH_MEMBER = 0x00002AFC, + ERROR_CLUB_NO_SUCH_INVITATION = 0x00002B00, + ERROR_CLUB_INVITATION_ALREADY_EXISTS = 0x00002B02, + ERROR_CLUB_INVALID_ROLE_ID = 0x00002B04, + ERROR_CLUB_INSUFFICIENT_PRIVILEGES = 0x00002B06, + ERROR_CLUB_INSUFFICIENT_PRIVACY_LEVEL = 0x00002B07, + ERROR_CLUB_INVALID_PRIVACY_LEVEL = 0x00002B08, + ERROR_CLUB_TOO_MANY_CLUBS_JOINED = 0x00002B09, + ERROR_CLUB_INVALID_ROLE_SET = 0x00002B0F, + ERROR_CLUB_NOT_SUBSCRIBED = 0x00002B15, + ERROR_CLUB_INVALID_CLUB_TYPE = 0x00002B19, + ERROR_CLUB_VOICE_FULL = 0x00002B1A, + ERROR_CLUB_MEMBER_SUBSCRIPTIONS_AT_MAX = 0x00002B1B, + ERROR_CLUB_SUGGESTION_ALREADY_EXISTS = 0x00002B20, + ERROR_CLUB_SUGGESTION_COUNT_AT_MAX = 0x00002B21, + ERROR_CLUB_NO_SUCH_SUGGESTION = 0x00002B22, + ERROR_CLUB_STREAM_NO_STREAM = 0x00002B5C, + ERROR_CLUB_STREAM_INVALID_NAME = 0x00002B5D, + ERROR_CLUB_STREAM_COUNT_AT_MIN = 0x00002B5E, + ERROR_CLUB_STREAM_COUNT_AT_MAX = 0x00002B5F, + ERROR_CLUB_STREAM_INVALID_VOICE_LEVEL = 0x00002B60, + ERROR_CLUB_STREAM_NO_SUCH_MESSAGE = 0x00002B61, + ERROR_CLUB_INVALID_AVATAR = 0x00002B75, + ERROR_CLUB_MEMBER_HAS_REQUIRED_ROLE = 0x00002B76, + ERROR_CLUB_INVALID_ROLE_CHANGE_REQUEST = 0x00002B77, + ERROR_CLUB_SENT_INVITATION_COUNT_AT_MAX = 0x00002B8E, + ERROR_CLUB_RECEIVED_INVITATION_COUNT_AT_MAX = 0x00002B8F, + ERROR_CLUB_TARGET_IS_BANNED = 0x00002B90, + ERROR_CLUB_NO_SUCH_BANNED_TARGET = 0x00002B91, + ERROR_CLUB_BAN_ALREADY_EXISTS = 0x00002B92, + ERROR_CLUB_BAN_COUNT_AT_MAX = 0x00002B93, + ERROR_CLUB_TICKET_COUNT_AT_MAX = 0x00002BA2, + ERROR_CLUB_TICKET_NO_SUCH_TICKET = 0x00002BA3, + ERROR_CLUB_TICKET_HAS_CONSUMED_ALLOWED_REDEEM_COUNT = 0x00002BA4, + + ERROR_CLUB_MEMBERSHIP_SUBSCRIPTIONS_AT_MAX = 0x00002E19, + ERROR_CLUB_MEMBERSHIP_PUSH_NOTIFICATION_REGISTRATIONS_AT_MAX = 0x00002E1A, + ERROR_CLUB_TAG_ALREADY_EXISTS = 0x00002E1B, + ERROR_CLUB_TAG_NO_SUCH_TAG = 0x00002E1C, + ERROR_CLUB_TAG_TOO_MANY_TAGS = 0x00002E1D, ERROR_REGISTRY_CREATE_KEY_ERROR = 0x00002EE0, ERROR_REGISTRY_OPEN_KEY_ERROR = 0x00002EE1, @@ -368,18 +367,10 @@ enum BattlenetRpcErrorCode : uint32 ERROR_REGISTRY_DELETE_ERROR = 0x00002EE5, ERROR_REGISTRY_ENCRYPT_ERROR = 0x00002EE6, ERROR_REGISTRY_DECRYPT_ERROR = 0x00002EE7, - ERROR_REGISTRY_KEY_SIZE_ERROR = 0x00002EE8, ERROR_REGISTRY_VALUE_SIZE_ERROR = 0x00002EE9, ERROR_REGISTRY_NOT_FOUND = 0x00002EEB, ERROR_REGISTRY_MALFORMED_STRING = 0x00002EEC, - ERROR_INTERFACE_ALREADY_CONNECTED = 0x000032C8, - ERROR_INTERFACE_NOT_READY = 0x000032C9, - ERROR_INTERFACE_OPTION_KEY_TOO_LARGE = 0x000032CA, - ERROR_INTERFACE_OPTION_VALUE_TOO_LARGE = 0x000032CB, - ERROR_INTERFACE_OPTION_KEY_INVALID_UTF8_STRING = 0x000032CC, - ERROR_INTERFACE_OPTION_VALUE_INVALID_UTF8_STRING = 0x000032CD, - ERROR_HTTP_COULDNT_RESOLVE = 0x000036B0, ERROR_HTTP_COULDNT_CONNECT = 0x000036B1, ERROR_HTTP_TIMEOUT = 0x000036B2, @@ -390,21 +381,55 @@ enum BattlenetRpcErrorCode : uint32 ERROR_HTTP_TOO_MANY_REDIRECTS = 0x000036B7, ERROR_HTTP_COULDNT_OPEN_FILE = 0x000036B8, ERROR_HTTP_COULDNT_CREATE_FILE = 0x000036B9, - ERROR_HTTP_COULDNT_READ_FILE = 0x000036BA, ERROR_HTTP_COULDNT_RENAME_FILE = 0x000036BB, ERROR_HTTP_COULDNT_CREATE_DIRECTORY = 0x000036BC, ERROR_HTTP_CURL_IS_NOT_READY = 0x000036BD, - ERROR_HTTP_CANCELLED = 0x000036BE, + ERROR_HTTP_CANCELED = 0x000036BE, + ERROR_HTTP_SEND_FAILED = 0x000036BF, + ERROR_HTTP_RECV_FAILED = 0x000036C0, + ERROR_HTTP_MALFORMED_REPLY = 0x000036C1, + ERROR_HTTP_ACCESS_DENIED = 0x000036C2, + ERROR_HTTP_MALFORMED_POST = 0x000036C3, + ERROR_HTTP_INVALID_CERT = 0x000036C4, + ERROR_HTTP_INVALID_CA_CERT = 0x000036C5, + ERROR_HTTP_SSL_CONNECT_FAILED = 0x000036C6, + ERROR_HTTP_PROTOCOL_FAILED = 0x000036C7, ERROR_HTTP_FILE_NOT_FOUND = 0x00003844, + ERROR_HTTP_OAUTH2_DISCOVERY_FAILED = 0x000038A5, + ERROR_HTTP_OAUTH2_TOKEN_REFRESH_FAILED = 0x000038A6, + ERROR_HTTP_OAUTH2_TOKEN_STORAGE_FAILED = 0x000038A7, + ERROR_HTTP_OAUTH2_TOKEN_EXCHANGE_FAILED = 0x000038A8, + ERROR_HTTP_OAUTH2_INVALID_CONTEXT = 0x000038A9, + + ERROR_ASTERION_GENERAL_RUNTIME = 0x00003A98, + ERROR_ASTERION_THROTTLED = 0x00003A99, + ERROR_ASTERION_SHARD_NOT_FOUND = 0x00003A9A, + ERROR_ASTERION_INVALID_PARAMETER = 0x00003A9B, + ERROR_ASTERION_REMOTE_REGION_UNAVAILABLE = 0x00003A9D, + ERROR_ASTERION_DEDUCT_RECORD_DUPLICATED = 0x00003A9F, + ERROR_ASTERION_DEDUCT_RECORD_MINIMUM_GAMETIME = 0x00003AA0, + ERROR_ASTERION_DEDUCT_RECORD_INVALID_STOP_TIME = 0x00003AA1, + ERROR_ASTERION_TIMED_OUT = 0x00003AA2, + ERROR_ASTERION_TOO_MANY_OUTSTANDING_REQUESTS = 0x00003AA3, + ERROR_ASTERION_DEDUCT_RECORD_ANOTHER_IN_PROGRESS = 0x00003AA4, + + ERROR_ASTERION_UNAVAILABLE = 0x00003E7F, + + ERROR_EVENT_VIEW_IS_FULL = 0x00003E80, + + ERROR_VOICE_ACCOUNT_NOT_FOUND = 0x00004268, + ERROR_VOICE_TOKEN_ALREADY_USED = 0x00004269, + ERROR_VOICE_VERSION_NOT_SUPPORTED = 0x0000426A, + ERROR_VOICE_INVALID_VERSION = 0x0000426B, + ERROR_VOICE_SECRET_KEY_STORAGE_FAILURE = 0x0000426C, + ERROR_ACCOUNT_MISSING_CONFIG = 0x00004650, ERROR_ACCOUNT_DATA_NOT_FOUND = 0x00004651, ERROR_ACCOUNT_ALREADY_SUBSCRIBED = 0x00004652, ERROR_ACCOUNT_NOT_SUBSCRIBED = 0x00004653, ERROR_ACCOUNT_FAILED_TO_PARSE_TIMEZONE_DATA = 0x00004654, - ERROR_ACCOUNT_LOAD_FAILED = 0x00004655, - ERROR_ACCOUNT_LOAD_CANCELLED = 0x00004656, ERROR_ACCOUNT_DATABASE_INVALIDATE_FAILED = 0x00004657, ERROR_ACCOUNT_CACHE_INVALIDATE_FAILED = 0x00004658, ERROR_ACCOUNT_SUBSCRIPTION_PENDING = 0x00004659, @@ -413,40 +438,20 @@ enum BattlenetRpcErrorCode : uint32 ERROR_ACCOUNT_UNDERAGE = 0x0000465C, ERROR_ACCOUNT_IDENTITY_CHECK_PENDING = 0x0000465D, ERROR_ACCOUNT_IDENTITY_UNVERIFIED = 0x0000465E, - - ERROR_DATABASE_BINDING_COUNT_MISMATCH = 0x00004A38, - ERROR_DATABASE_BINDING_PARSE_FAIL = 0x00004A39, - ERROR_DATABASE_RESULTSET_COLUMNS_MISMATCH = 0x00004A3A, - ERROR_DATABASE_DEADLOCK = 0x00004A3B, - ERROR_DATABASE_DUPLICATE_KEY = 0x00004A3C, - ERROR_DATABASE_CANNOT_CONNECT = 0x00004A3D, - ERROR_DATABASE_STATEMENT_FAILED = 0x00004A3E, - ERROR_DATABASE_TRANSACTION_NOT_STARTED = 0x00004A3F, - ERROR_DATABASE_TRANSACTION_NOT_ENDED = 0x00004A40, - ERROR_DATABASE_TRANSACTION_LEAK = 0x00004A41, - ERROR_DATABASE_TRANSACTION_STATE_BAD = 0x00004A42, - ERROR_DATABASE_SERVER_GONE = 0x00004A43, - ERROR_DATABASE_QUERY_TIMEOUT = 0x00004A44, - ERROR_DATABASE_BINDING_NOT_NULLABLE = 0x00004A9C, - ERROR_DATABASE_BINDING_INVALID_INTEGER = 0x00004A9D, - ERROR_DATABASE_BINDING_INVALID_FLOAT = 0x00004A9E, - ERROR_DATABASE_BINDING_INVALID_TEMPORAL = 0x00004A9F, - ERROR_DATABASE_BINDING_INVALID_PROTOBUF = 0x00004AA0, - - ERROR_PARTY_INVALID_PARTY_ID = 0x00004E20, - ERROR_PARTY_ALREADY_IN_PARTY = 0x00004E21, - ERROR_PARTY_NOT_IN_PARTY = 0x00004E22, - ERROR_PARTY_INVITATION_UNDELIVERABLE = 0x00004E23, - ERROR_PARTY_INVITATION_ALREADY_EXISTS = 0x00004E24, - ERROR_PARTY_TOO_MANY_PARTY_INVITATIONS = 0x00004E25, - ERROR_PARTY_TOO_MANY_RECEIVED_INVITATIONS = 0x00004E26, - ERROR_PARTY_NO_SUCH_TYPE = 0x00004E27, + ERROR_ACCOUNT_IGR = 0x0000465F, + ERROR_GAME_ACCOUNT_CREATE_NEED_NATIONAL_ID = 0x00004660, + ERROR_GAME_ACCOUNT_CREATE_BLOCKED = 0x00004661, + ERROR_GAME_ACCOUNT_DETACHED = 0x00004662, + ERROR_GAME_ACCOUNT_CREATE_TOO_MANY_GAME_ACCOUNT = 0x00004663, + ERROR_SUBSCRIBER_NO_NEED_TO_UPDATE = 0x00004664, + ERROR_ACCOUNT_MOBILE_NUMBER_REQUIRED = 0x00004665, + ERROR_ACCOUNT_MOBILE_NUMBER_ALREADY_USED = 0x00004666, + ERROR_ACCOUNT_DATA_NOT_EXISTS_IN_CACHE = 0x00004667, + ERROR_ACCOUNT_INVALID_IDENTITY_DATA = 0x00004668, ERROR_GAMES_NO_SUCH_FACTORY = 0x000055F0, ERROR_GAMES_NO_SUCH_GAME = 0x000055F1, ERROR_GAMES_NO_SUCH_REQUEST = 0x000055F2, - ERROR_GAMES_NO_SUCH_PARTY_MEMBER = 0x000055F3, - ERROR_RESOURCES_OFFLINE = 0x000059D8, ERROR_GAME_SERVER_CREATE_GAME_REFUSED = 0x00005DC0, @@ -470,11 +475,8 @@ enum BattlenetRpcErrorCode : uint32 ERROR_GAME_MASTER_REGISTER_FAILED = 0x000061AB, ERROR_GAME_MASTER_NO_GAME_SERVER = 0x000061AC, ERROR_GAME_MASTER_NO_UTILITY_SERVER = 0x000061AD, - ERROR_GAME_MASTER_NO_GAME_VERSION = 0x000061AE, ERROR_GAME_MASTER_GAME_JOIN_FAILED = 0x000061AF, - ERROR_GAME_MASTER_ALREADY_REGISTERED = 0x000061B0, ERROR_GAME_MASTER_NO_FACTORY = 0x000061B1, - ERROR_GAME_MASTER_MULTIPLE_GAME_VERSIONS = 0x000061B2, ERROR_GAME_MASTER_INVALID_PLAYER = 0x000061B3, ERROR_GAME_MASTER_INVALID_GAME_REQUEST = 0x000061B4, ERROR_GAME_MASTER_INSUFFICIENT_PRIVILEGES = 0x000061B5, @@ -488,43 +490,50 @@ enum BattlenetRpcErrorCode : uint32 ERROR_GAME_MASTER_INVALID_TEAM_ID = 0x000061BD, ERROR_GAME_MASTER_CREATION_IN_PROGRESS = 0x000061BE, - ERROR_NOTIFICATION_INVALID_CLIENT_ID = 0x00006590, - ERROR_NOTIFICATION_DUPLICATE_NAME = 0x00006591, - ERROR_NOTIFICATION_NAME_NOT_FOUND = 0x00006592, - ERROR_NOTIFICATION_INVALID_SERVER = 0x00006593, ERROR_NOTIFICATION_QUOTA_EXCEEDED = 0x00006594, ERROR_NOTIFICATION_INVALID_NOTIFICATION_TYPE = 0x00006595, ERROR_NOTIFICATION_UNDELIVERABLE = 0x00006596, ERROR_NOTIFICATION_UNDELIVERABLE_TEMPORARY = 0x00006597, - ERROR_ACHIEVEMENTS_NOTHING_TO_UPDATE = 0x00006D60, - ERROR_ACHIEVEMENTS_INVALID_PARAMS = 0x00006D61, - ERROR_ACHIEVEMENTS_NOT_REGISTERED = 0x00006D62, - ERROR_ACHIEVEMENTS_NOT_READY = 0x00006D63, - ERROR_ACHIEVEMENTS_FAILED_TO_PARSE_STATIC_DATA = 0x00006D64, - ERROR_ACHIEVEMENTS_UNKNOWN_ID = 0x00006D65, - ERROR_ACHIEVEMENTS_MISSING_SNAPSHOT = 0x00006D66, - ERROR_ACHIEVEMENTS_ALREADY_REGISTERED = 0x00006D67, - ERROR_ACHIEVEMENTS_TOO_MANY_REGISTRATIONS = 0x00006D68, - ERROR_ACHIEVEMENTS_ALREADY_IN_PROGRESS = 0x00006D69, - ERROR_ACHIEVEMENTS_TEMPORARY_OUTAGE = 0x00006D6A, - ERROR_ACHIEVEMENTS_INVALID_PROGRAMID = 0x00006D6B, - ERROR_ACHIEVEMENTS_MISSING_RECORD = 0x00006D6C, - ERROR_ACHIEVEMENTS_REGISTRATION_PENDING = 0x00006D6D, - ERROR_ACHIEVEMENTS_ENTITY_ID_NOT_FOUND = 0x00006D6E, - ERROR_ACHIEVEMENTS_ACHIEVEMENT_ID_NOT_FOUND = 0x00006D6F, - ERROR_ACHIEVEMENTS_CRITERIA_ID_NOT_FOUND = 0x00006D70, - ERROR_ACHIEVEMENTS_STATIC_DATA_MISMATCH = 0x00006D71, - ERROR_ACHIEVEMENTS_WRONG_THREAD = 0x00006D72, - ERROR_ACHIEVEMENTS_CALLBACK_IS_NULL = 0x00006D73, - ERROR_ACHIEVEMENTS_AUTO_REGISTER_PENDING = 0x00006D74, - ERROR_ACHIEVEMENTS_NOT_INITIALIZED = 0x00006D75, - ERROR_ACHIEVEMENTS_ACHIEVEMENT_ID_ALREADY_EXISTS = 0x00006D76, - ERROR_ACHIEVEMENTS_FAILED_TO_DOWNLOAD_STATIC_DATA = 0x00006D77, - ERROR_ACHIEVEMENTS_STATIC_DATA_NOT_FOUND = 0x00006D78, + ERROR_LEADERBOARD_RULE_NOT_FOUND = 0x00006D61, + ERROR_LEADERBOARD_NOT_FOUND = 0x00006D62, + ERROR_LEADERBOARD_INVALID_ENTITY_ID = 0x00006D64, + ERROR_LEADERBOARD_INVALID_GAME_ACCOUNT = 0x00006D65, + ERROR_LEADERBOARD_INVALID_TIMESTAMP = 0x00006D66, + ERROR_LEADERBOARD_INVALID_TAGS = 0x00006D67, + ERROR_LEADERBOARD_INVALID_PAYLOAD = 0x00006D69, + ERROR_LEADERBOARD_INVALID_TITLE_ID = 0x00006D6A, + ERROR_LEADERBOARD_INVALID_RULE_NAME = 0x00006D6B, + ERROR_LEADERBOARD_INVALID_REQUEST = 0x00006D6C, + ERROR_LEADERBOARD_INVALID_SCORES = 0x00006D6D, + ERROR_LEADERBOARD_INVALID_FIELD_FORMAT = 0x00006D6E, + ERROR_LEADERBOARD_ACCOUNT_NOT_FOUND = 0x00006D6F, + ERROR_LEADERBOARD_RANKS_NOT_FOUND = 0x00006D70, + ERROR_LEADERBOARD_INVALID_BATCH_SUBMIT_RANKS_REQUEST = 0x00006D71, + + ERROR_MATCHMAKING_MATCHMAKER_NOT_FOUND = 0x00007530, + ERROR_MATCHMAKING_MATCHMAKER_DECOMMISSIONED = 0x00007531, + ERROR_MATCHMAKING_GAMESERVER_NOT_FOUND = 0x00007532, + ERROR_MATCHMAKING_30003 = 0x00007533, + ERROR_MATCHMAKING_MATCHMAKER_ALREADY_REGISTERED = 0x00007534, + ERROR_MATCHMAKING_GAMESERVER_ALREADY_REGISTERED = 0x00007535, + ERROR_MATCHMAKING_REQUEST_ID_NOT_FOUND = 0x00007536, + ERROR_MATCHMAKING_INSUFFICIENT_PARTY_PRIVILEGES = 0x00007537, + ERROR_MATCHMAKING_EVENT_QUEUE_FULL = 0x00007538, + ERROR_MATCHMAKING_CANCEL_NOT_ALLOWED = 0x00007539, + ERROR_MATCHMAKING_PLAYER_NOT_CONNECTED = 0x0000753A, + ERROR_MATCHMAKING_EVENT_CANCELED = 0x0000753B, + ERROR_MATCHMAKING_GAMESERVER_FULL = 0x0000753C, + ERROR_MATCHMAKING_INVALID_RESPONSE = 0x0000753D, + ERROR_MATCHMAKING_MATCHMAKER_INVALID_CONNECTION = 0x0000753E, + + ERROR_MATCHMAKING_SERVER_ALREADY_IN_GAME = 0x00007918, + ERROR_MATCHMAKING_SERVER_INVALID_GAME = 0x00007919, + ERROR_MATCHMAKING_SERVER_INVALID_PLAYER = 0x0000791A, + ERROR_MATCHMAKING_SERVER_GAME_FULL = 0x0000791B, + ERROR_MATCHMAKING_SERVER_UNKNOWN_REQUEST_ID = 0x0000791C, ERROR_GAME_UTILITY_SERVER_VARIABLE_REQUEST_REFUSED = 0x000084D1, - ERROR_GAME_UTILITY_SERVER_WRONG_NUMBER_OF_VARIABLES_RETURNED = 0x000084D2, ERROR_GAME_UTILITY_SERVER_CLIENT_REQUEST_REFUSED = 0x000084D3, ERROR_GAME_UTILITY_SERVER_PRESENCE_CHANNEL_CREATED_REFUSED = 0x000084D4, ERROR_GAME_UTILITY_SERVER_VARIABLE_REQUEST_REFUSED_TRANSIENT = 0x00008502, @@ -535,31 +544,34 @@ enum BattlenetRpcErrorCode : uint32 ERROR_GAME_UTILITY_SERVER_CLIENT_REQUEST_REFUSED_BUSY = 0x00008535, ERROR_GAME_UTILITY_SERVER_PRESENCE_CHANNEL_CREATED_REFUSED_BUSY = 0x00008536, ERROR_GAME_UTILITY_SERVER_SERVER_REQUEST_REFUSED_BUSY = 0x00008537, - ERROR_GAME_UTILITY_SERVER_NO_SERVER = 0x00008598, - ERROR_IDENTITY_INSUFFICIENT_DATA = 0x0000A028, - ERROR_IDENTITY_TOO_MANY_RESULTS = 0x0000A029, - ERROR_IDENTITY_BAD_ID = 0x0000A02A, - ERROR_IDENTITY_NO_ACCOUNT_BLOB = 0x0000A02B, + ERROR_GAME_UTILITY_SERVER_REQUEST_REFUSED = 0x00008567, + ERROR_GAME_UTILITY_SERVER_REQUEST_REFUSED_BUSY = 0x00008568, + ERROR_GAME_UTILITY_SERVER_REQUEST_REFUSED_TRANSIENT = 0x00008569, + ERROR_GAME_UTILITY_SERVER_NO_SERVER = 0x00008598, + ERROR_GAME_UTILITY_SERVER_VERSION_MISMATCH = 0x0000859A, + ERROR_GAME_UTILITY_SERVER_TIMED_OUT = 0x0000859B, + + ERROR_SESSION_ADMIN_KICK = 0x00009C44, + ERROR_SESSION_ABANDONED = 0x00009C48, + ERROR_SESSION_CAIS_PLAYTIME_EXCEEDED = 0x00009C4B, + ERROR_SESSION_CAIS_CURFEW = 0x00009C4C, + ERROR_SESSION_INVALID_NID = 0x00009C4E, + ERROR_SESSION_QUEUE_DUPLICATED = 0x00009C4F, + ERROR_SESSION_QUEUE_ADMIN_KICK = 0x00009C51, + ERROR_SESSION_KEY_EXPIRED = 0x00009C52, + ERROR_SESSION_TOKEN_EXPIRED = 0x00009C53, - ERROR_RISK_CHALLENGE_ACTION = 0x0000A410, - ERROR_RISK_DELAY_ACTION = 0x0000A411, ERROR_RISK_THROTTLE_ACTION = 0x0000A412, ERROR_RISK_ACCOUNT_LOCKED = 0x0000A413, - ERROR_RISK_CS_DENIED = 0x0000A414, ERROR_RISK_DISCONNECT_ACCOUNT = 0x0000A415, ERROR_RISK_CHECK_SKIPPED = 0x0000A416, ERROR_REPORT_UNAVAILABLE = 0x0000AFC8, - ERROR_REPORT_TOO_LARGE = 0x0000AFC9, + ERROR_REPORT_UNKNOWN_PROGRAM = 0x0000AFC9, ERROR_REPORT_UNKNOWN_TYPE = 0x0000AFCA, - ERROR_REPORT_ATTRIBUTE_INVALID = 0x0000AFCB, ERROR_REPORT_ATTRIBUTE_QUOTA_EXCEEDED = 0x0000AFCC, ERROR_REPORT_UNCONFIRMED = 0x0000AFCD, - ERROR_REPORT_NOT_CONNECTED = 0x0000AFCE, - ERROR_REPORT_REJECTED = 0x0000AFCF, - ERROR_REPORT_TOO_MANY_REQUESTS = 0x0000AFD0, - ERROR_ACCOUNT_ALREADY_REGISTERD = 0x0000BB80, ERROR_ACCOUNT_NOT_REGISTERED = 0x0000BB81, ERROR_ACCOUNT_REGISTRATION_PENDING = 0x0000BB82, |