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