TrinityCore
Loading...
Searching...
No Matches
ClubService.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "ClubService.h"
20#include "ClientBuildInfo.h"
22#include "GameTime.h"
23#include "Guild.h"
24#include "Player.h"
25#include "SocialMgr.h"
26#include "api/client/v1/club_listener.pb.h"
27
28namespace Battlenet::Services
29{
31
32uint32 ClubService::HandleGetClubType(club::v1::client::GetClubTypeRequest const* request, club::v1::client::GetClubTypeResponse* response,
33 std::function<void(ServiceBase*, uint32, google::protobuf::Message const*)>& /*continuation*/)
34{
35 // We only support guilds for now.
36 if (request->type().name() == "guild")
37 {
38 response->set_allocated_type(CreateGuildClubType().release());
39 return ERROR_OK;
40 }
41
43}
44
45uint32 ClubService::HandleSubscribe(club::v1::client::SubscribeRequest const* /*request*/, NoData* /*response*/,
46 std::function<void(ServiceBase*, uint32, google::protobuf::Message const*)>& /*continuation*/)
47{
48 Player const* player = _session->GetPlayer();
49
50 if (!player)
51 return ERROR_INTERNAL;
52
53 Guild const* guild = player->GetGuild();
54
55 if (!guild)
56 return ERROR_CLUB_NO_CLUB;
57
58 // Subscibe the client to it's own guild club.
59 club::v1::client::SubscribeNotification subscribeNotification;
60
61 Guild::Member const* guildMember = guild->GetMember(player->GetGUID());
62
63 if (!guildMember)
65
66 Guild::Member const* guildLeader = guild->GetMember(guild->GetLeaderGUID());
67
68 if (!guildLeader)
70
71 subscribeNotification.set_club_id(guild->GetId());
72 subscribeNotification.set_allocated_agent_id(ClubMembershipService::CreateClubMemberId(player->GetGUID()).release());
73
74 club::v1::client::Club* guildClub = subscribeNotification.mutable_club();
75
76 guildClub->set_id(guild->GetId());
77 guildClub->set_allocated_type(CreateGuildClubType().release());
78 guildClub->set_name(guild->GetName());
79
80 // These are not related to normal guild functionality so we hardcode them for now.
81 guildClub->set_privacy_level(club::v1::PrivacyLevel::PRIVACY_LEVEL_OPEN);
82 guildClub->set_visibility_level(club::v1::VISIBILITY_LEVEL_PRIVATE);
83
84 guildClub->set_member_count(guild->GetMembersCount());
85
86 // Set the club leader, guild master in this case.
87 club::v1::client::MemberDescription* guildLeaderDescription = guildClub->add_leader();
88
89 guildLeaderDescription->mutable_id()->set_account_id(guildLeader->GetAccountId());
90 guildLeaderDescription->mutable_id()->set_unique_id(guildLeader->GetGUID().GetCounter());
91
92 club::v1::client::Member* subscriber = subscribeNotification.mutable_member();
93
94 // The member sending the notification data.
95 subscriber->set_allocated_id(ClubMembershipService::CreateClubMemberId(player->GetGUID()).release());
96
97 // Community/Club default roles have slightly different values.
98 // Also this is required to set the current leader/guild master symbol in the interface.
99 // 1 = Owner, 4 = Member. Once communities are fully implemented these will go into a new database table.
100 if (guildMember->IsRank(GuildRankId::GuildMaster))
101 subscriber->add_role(AsUnderlyingType(ClubRoleIdentifier::Owner));
103 subscriber->add_role(AsUnderlyingType(ClubRoleIdentifier::Moderator));
104 else
105 subscriber->add_role(AsUnderlyingType(ClubRoleIdentifier::Member));
106
107 subscriber->set_presence_level(club::v1::client::PRESENCE_LEVEL_RICH);
108 subscriber->set_whisper_level(club::v1::client::WHISPER_LEVEL_OPEN);
109
110 // Member is online and active.
111 subscriber->set_active(true);
112
113 WorldserverService<club::v1::client::ClubListener>(_session).OnSubscribe(&subscribeNotification, true, true);
114
115 // Notify the client about the changed club state.
116 club::v1::client::SubscriberStateChangedNotification subscriberStateChangedNotification;
117
118 subscriberStateChangedNotification.set_club_id(guild->GetId());
119
120 club::v1::client::SubscriberStateAssignment* assignment = subscriberStateChangedNotification.add_assignment();
121
122 assignment->set_allocated_member_id(ClubMembershipService::CreateClubMemberId(player->GetGUID()).release());
123
124 // Member is online and active.
125 assignment->set_active(true);
126
127 WorldserverService<club::v1::client::ClubListener>(_session).OnSubscriberStateChanged(&subscriberStateChangedNotification, true, true);
128
129 return ERROR_OK;
130}
131
132uint32 ClubService::HandleGetMembers(club::v1::client::GetMembersRequest const* /*request*/, club::v1::client::GetMembersResponse* response,
133 std::function<void(ServiceBase*, uint32, google::protobuf::Message const*)>& /*continuation*/)
134{
135 Player const* player = _session->GetPlayer();
136
137 if (!player)
138 return ERROR_INTERNAL;
139
140 Guild const* guild = player->GetGuild();
141
142 if (!guild)
143 return ERROR_CLUB_NO_CLUB;
144
145 response->mutable_member()->Reserve(guild->GetMembersCount());
146
147 for (auto const& [guid, member] : guild->GetMembers())
148 {
149 club::v1::client::Member* clubMember = response->add_member();
150
151 clubMember->set_allocated_id(ClubMembershipService::CreateClubMemberId(guid).release());
152
153 // Community/Club default roles have slightly different values.
154 // When communities are implemented those are going to be database fields.
155 if (member.IsRank(GuildRankId::GuildMaster))
156 clubMember->add_role(AsUnderlyingType(ClubRoleIdentifier::Owner));
157 else if (guild->HasAnyRankRight(member.GetRankId(), GuildRankRights(GR_RIGHT_OFFCHATLISTEN | GR_RIGHT_OFFCHATSPEAK)))
158 clubMember->add_role(AsUnderlyingType(ClubRoleIdentifier::Moderator));
159 else
160 clubMember->add_role(AsUnderlyingType(ClubRoleIdentifier::Member));
161
162 clubMember->set_presence_level(club::v1::client::PresenceLevel::PRESENCE_LEVEL_RICH);
163 clubMember->set_whisper_level(club::v1::client::WhisperLevel::WHISPER_LEVEL_OPEN);
164 std::string_view publicNote = member.GetPublicNote();
165 clubMember->set_note(publicNote.data(), publicNote.size());
166 clubMember->set_active(member.IsOnline());
167 }
168
169 return ERROR_OK;
170}
171
172uint32 ClubService::HandleGetStreams(club::v1::client::GetStreamsRequest const* /*request*/, club::v1::client::GetStreamsResponse* response,
173 std::function<void(ServiceBase*, uint32, google::protobuf::Message const*)>& /*continuation*/)
174{
175 Player const* player = _session->GetPlayer();
176
177 if (!player)
178 return ERROR_INTERNAL;
179
180 Guild const* guild = player->GetGuild();
181
182 if (!guild)
183 return ERROR_CLUB_NO_CLUB;
184
185 // General guild channel.
186 club::v1::client::Stream* generalGuildChannelStream = response->add_stream();
187
188 generalGuildChannelStream->set_club_id(guild->GetId());
189 generalGuildChannelStream->set_id(AsUnderlyingType(ClubStreamType::Guild));
190
191 v2::Attribute* generalStreamAttribute = generalGuildChannelStream->add_attribute();
192
193 generalStreamAttribute->set_name("global_strings_tag");
194 generalStreamAttribute->mutable_value()->set_string_value("COMMUNITIES_GUILD_GENERAL_CHANNEL_NAME");
195
196 generalGuildChannelStream->set_name("Guild");
197
198 // All roles got access to this channel.
199 // Club roles are currently guild role + 1.
200 // With a complete club/community system those will be handled differently.
201 generalGuildChannelStream->mutable_access()->add_role(AsUnderlyingType(ClubRoleIdentifier::Owner));
202 generalGuildChannelStream->mutable_access()->add_role(AsUnderlyingType(ClubRoleIdentifier::Leader));
203 generalGuildChannelStream->mutable_access()->add_role(AsUnderlyingType(ClubRoleIdentifier::Moderator));
204 generalGuildChannelStream->mutable_access()->add_role(AsUnderlyingType(ClubRoleIdentifier::Member));
205
206 // No voice support.
207 generalGuildChannelStream->set_voice_level(club::v1::client::StreamVoiceLevel::VOICE_LEVEL_DISABLED);
208
209 // Officer guild channel.
210 club::v1::client::Stream* officerGuildChannelStream = response->add_stream();
211
212 officerGuildChannelStream->set_club_id(guild->GetId());
213 officerGuildChannelStream->set_id(AsUnderlyingType(ClubStreamType::Officer));
214
215 v2::Attribute* officerStreamAttribute = officerGuildChannelStream->add_attribute();
216
217 officerStreamAttribute->set_name("global_strings_tag");
218 officerStreamAttribute->mutable_value()->set_string_value("COMMUNITIES_GUILD_OFFICER_CHANNEL_NAME");
219
220 officerGuildChannelStream->set_name("Officer");
221
222 // All roles got access to this channel.
223 // Club roles are currently guild role + 1.
224 // With a complete club/community system those will be handled differently.
225 officerGuildChannelStream->mutable_access()->add_role(AsUnderlyingType(ClubRoleIdentifier::Owner));
226 officerGuildChannelStream->mutable_access()->add_role(AsUnderlyingType(ClubRoleIdentifier::Leader));
227 officerGuildChannelStream->mutable_access()->add_role(AsUnderlyingType(ClubRoleIdentifier::Moderator));
228
229 // No voice support.
230 officerGuildChannelStream->set_voice_level(club::v1::client::StreamVoiceLevel::VOICE_LEVEL_DISABLED);
231
232 // Enable channel view
233 club::v1::client::StreamView* generalView = response->add_view();
234
235 generalView->set_club_id(guild->GetId());
236 generalView->set_stream_id(AsUnderlyingType(ClubStreamType::Guild));
237
238 club::v1::client::StreamView* officerView = response->add_view();
239
240 officerView->set_club_id(guild->GetId());
241 officerView->set_stream_id(AsUnderlyingType(ClubStreamType::Officer));
242
243 return ERROR_OK;
244}
245
246uint32 ClubService::HandleSubscribeStream(club::v1::client::SubscribeStreamRequest const* request, NoData* /*response*/,
247 std::function<void(ServiceBase*, uint32, google::protobuf::Message const*)>& /*continuation*/)
248{
249 Player const* player = _session->GetPlayer();
250
251 if (!player)
252 return ERROR_INTERNAL;
253
254 Guild const* guild = player->GetGuild();
255
256 if (!guild)
257 return ERROR_CLUB_NO_CLUB;
258
259 // Basic sanity check until full communities are implemented.
260 // 1 - Guild, 2 - Officer chat stream.
261 if (request->stream_id().empty() || (request->stream_id().Get(0) != AsUnderlyingType(ClubStreamType::Guild) && request->stream_id().Get(0) != AsUnderlyingType(ClubStreamType::Officer)))
263
264 return ERROR_OK;
265}
266
267uint32 ClubService::HandleUnsubscribeStream(club::v1::client::UnsubscribeStreamRequest const* /*request*/, NoData* /*response*/,
268 std::function<void(ServiceBase*, uint32, google::protobuf::Message const*)>& /*continuation*/)
269{
270 // We just have to signal the client that the unsubscribe request came through.
271 return ERROR_OK;
272}
273
274uint32 ClubService::HandleSetStreamFocus(club::v1::client::SetStreamFocusRequest const* /*request*/, NoData* /*response*/,
275 std::function<void(ServiceBase*, uint32, google::protobuf::Message const*)>& /*continuation*/)
276{
277 Player const* player = _session->GetPlayer();
278
279 if (!player)
280 return ERROR_INTERNAL;
281
282 Guild const* guild = player->GetGuild();
283
284 if (!guild)
286
287 return ERROR_OK;
288}
289
290uint32 ClubService::HandleAdvanceStreamViewTime(club::v1::client::AdvanceStreamViewTimeRequest const* /*request*/, NoData* /*response*/,
291 std::function<void(ServiceBase*, uint32, google::protobuf::Message const*)>& /*continuation*/)
292{
293 Player const* player = _session->GetPlayer();
294
295 if (!player)
296 return ERROR_INTERNAL;
297
298 Guild const* guild = player->GetGuild();
299
300 if (!guild)
302
303 return ERROR_OK;
304}
305
306uint32 ClubService::HandleCreateMessage(club::v1::client::CreateMessageRequest const* request, club::v1::client::CreateMessageResponse* response,
307 std::function<void(ServiceBase*, uint32, google::protobuf::Message const*)>& continuation)
308{
309 // Basic sanity check until full communities are implemented.
310 // 1 - Guild, 2 - Officer chat stream.
311 if (request->stream_id() != AsUnderlyingType(ClubStreamType::Guild) && request->stream_id() != AsUnderlyingType(ClubStreamType::Officer))
313
314 // Just some sanity checks. We do not care about the requested stream for now since we only have two.
315 Player const* player = _session->GetPlayer();
316
317 if (!player)
318 return ERROR_INTERNAL;
319
320 Guild const* guild = player->GetGuild();
321
322 if (!guild)
323 return ERROR_CLUB_NO_CLUB;
324
325 GuildRankRights requiredRights = { };
326 ChatMessageResult result = { };
327
328 switch (ClubStreamType(request->stream_id()))
329 {
331 requiredRights = GR_RIGHT_GCHATLISTEN;
332 result = _session->HandleChatMessage(CHAT_MSG_GUILD, LANG_UNIVERSAL, request->options().content());
333 break;
335 requiredRights = GR_RIGHT_OFFCHATLISTEN;
336 result = _session->HandleChatMessage(CHAT_MSG_OFFICER, LANG_UNIVERSAL, request->options().content());
337 break;
338 default:
340 }
341
342 if (result == ChatMessageResult::Ok)
343 {
344 std::chrono::microseconds messageTime = std::chrono::duration_cast<std::chrono::microseconds>(GameTime::GetSystemTime().time_since_epoch());
345
346 FillStreamMessage(response->mutable_message(), request->options().content(), messageTime, player->GetGUID());
347
348 club::v1::client::StreamMessageAddedNotification messageAddedNotification;
349 messageAddedNotification.set_allocated_agent_id(ClubMembershipService::CreateClubMemberId(player->GetGUID()).release());
350 messageAddedNotification.set_club_id(guild->GetId());
351 messageAddedNotification.set_stream_id(request->stream_id());
352 FillStreamMessage(messageAddedNotification.mutable_message(), request->options().content(), messageTime, player->GetGUID());
353
354 guild->BroadcastWorker([&](Player const* receiver)
355 {
356 Guild::Member const* receiverMember = guild->GetMember(receiver->GetGUID());
357 if (!guild->HasAnyRankRight(receiverMember->GetRankId(), requiredRights))
358 return;
359
360 if (receiver->GetSocial()->HasIgnore(player->GetGUID(), _session->GetAccountGUID()))
361 return;
362
363 WorldserverService<club::v1::client::ClubListener>(receiver->GetSession()).OnStreamMessageAdded(&messageAddedNotification, true, true);
364 }, player);
365
366 return ERROR_OK;
367 }
368
369 // If the message is empty there should never be a response to message request.
370 continuation = nullptr;
371
373}
374
375std::unique_ptr<club::v1::UniqueClubType> ClubService::CreateGuildClubType()
376{
377 std::unique_ptr<club::v1::UniqueClubType> type = std::make_unique<club::v1::UniqueClubType>();
378 type->set_program(ClientBuild::Program::WoW);
379 type->set_name("guild");
380 return type;
381}
382
383void ClubService::FillStreamMessage(club::v1::client::StreamMessage* message, std::string_view msg, std::chrono::microseconds messageTime, ObjectGuid author)
384{
385 message->mutable_id()->set_epoch(messageTime.count());
386 message->mutable_id()->set_position(0);
387
388 message->mutable_author()->set_allocated_id(ClubMembershipService::CreateClubMemberId(author).release());
389
390 club::v1::client::ContentChain* contentChain = message->add_content_chain();
391
392 contentChain->set_content(msg.data(), msg.size());
393 contentChain->set_edit_time(messageTime.count());
394}
395}
@ ERROR_CLUB_NO_SUCH_MEMBER
@ ERROR_CLUB_NOT_MEMBER
@ ERROR_CLUB_NO_CLUB
@ ERROR_CLUB_STREAM_NO_SUCH_MESSAGE
@ ERROR_CLUB_STREAM_NO_STREAM
@ ERROR_NOT_IMPLEMENTED
uint32_t uint32
Definition Define.h:154
ClubStreamType
Definition Guild.h:88
GuildRankRights
Definition Guild.h:103
@ GR_RIGHT_OFFCHATSPEAK
Definition Guild.h:108
@ GR_RIGHT_OFFCHATLISTEN
Definition Guild.h:107
@ GR_RIGHT_GCHATLISTEN
Definition Guild.h:105
@ LANG_UNIVERSAL
ChatMessageResult
@ CHAT_MSG_GUILD
@ CHAT_MSG_OFFICER
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition Util.h:565
ObjectGuid const & GetGUID() const
Definition BaseEntity.h:163
static std::unique_ptr< club::v1::MemberId > CreateClubMemberId(ObjectGuid guid)
uint32 HandleSubscribeStream(club::v1::client::SubscribeStreamRequest const *request, NoData *response, std::function< void(ServiceBase *, uint32, ::google::protobuf::Message const *)> &continuation) override
uint32 HandleGetClubType(club::v1::client::GetClubTypeRequest const *request, club::v1::client::GetClubTypeResponse *response, std::function< void(ServiceBase *, uint32, ::google::protobuf::Message const *)> &continuation) override
uint32 HandleUnsubscribeStream(club::v1::client::UnsubscribeStreamRequest const *request, NoData *response, std::function< void(ServiceBase *, uint32, ::google::protobuf::Message const *)> &continuation) override
uint32 HandleSubscribe(club::v1::client::SubscribeRequest const *request, NoData *response, std::function< void(ServiceBase *, uint32, ::google::protobuf::Message const *)> &continuation) override
ClubService(WorldSession *session)
uint32 HandleGetStreams(club::v1::client::GetStreamsRequest const *request, club::v1::client::GetStreamsResponse *response, std::function< void(ServiceBase *, uint32, ::google::protobuf::Message const *)> &continuation) override
uint32 HandleAdvanceStreamViewTime(club::v1::client::AdvanceStreamViewTimeRequest const *request, NoData *response, std::function< void(ServiceBase *, uint32, ::google::protobuf::Message const *)> &continuation) override
uint32 HandleCreateMessage(club::v1::client::CreateMessageRequest const *request, club::v1::client::CreateMessageResponse *response, std::function< void(ServiceBase *, uint32, ::google::protobuf::Message const *)> &continuation) override
static void FillStreamMessage(club::v1::client::StreamMessage *message, std::string_view msg, std::chrono::microseconds messageTime, ObjectGuid author)
uint32 HandleGetMembers(club::v1::client::GetMembersRequest const *request, club::v1::client::GetMembersResponse *response, std::function< void(ServiceBase *, uint32, ::google::protobuf::Message const *)> &continuation) override
static std::unique_ptr< club::v1::UniqueClubType > CreateGuildClubType()
uint32 HandleSetStreamFocus(club::v1::client::SetStreamFocusRequest const *request, NoData *response, std::function< void(ServiceBase *, uint32, ::google::protobuf::Message const *)> &continuation) override
GuildRankId GetRankId() const
Definition Guild.h:357
uint32 GetAccountId() const
Definition Guild.h:356
bool IsRank(GuildRankId rankId) const
Definition Guild.h:382
ObjectGuid const & GetGUID() const
Definition Guild.h:354
Definition Guild.h:329
ObjectGuid GetLeaderGUID() const
Definition Guild.h:756
ObjectGuid::LowType GetId() const
Definition Guild.h:754
std::string const & GetName() const
Definition Guild.h:757
void BroadcastWorker(Do &&_do, Player const *except=nullptr) const
Definition Guild.h:838
std::unordered_map< ObjectGuid, Member > const & GetMembers() const
Definition Guild.h:853
bool HasAnyRankRight(GuildRankId rankId, GuildRankRights rights) const
Definition Guild.cpp:3139
Member const * GetMember(ObjectGuid const &guid) const
Definition Guild.h:923
uint32 GetMembersCount() const
Definition Guild.h:852
LowType GetCounter() const
Definition ObjectGuid.h:336
bool HasIgnore(ObjectGuid const &ignoreGuid, ObjectGuid const &ignoreAccountGuid)
PlayerSocial * GetSocial() const
Definition Player.h:1274
Guild * GetGuild()
Definition Player.cpp:30428
WorldSession * GetSession() const
Definition Player.h:2256
Player session in the World.
ObjectGuid GetAccountGUID() const
Player * GetPlayer() const
ChatMessageResult HandleChatMessage(ChatMsg type, Language lang, std::string msg, std::string target="", Optional< ObjectGuid > targetGuid={})
SystemTimePoint GetSystemTime()
Current chrono system_clock time point.
Definition GameTime.cpp:62
static constexpr Id WoW