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"
21#include "GameTime.h"
22#include "Guild.h"
23#include "Player.h"
24#include "SocialMgr.h"
26
27namespace Battlenet::Services
28{
30
31uint32 ClubService::HandleGetClubType(club::v1::client::GetClubTypeRequest const* request, club::v1::client::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::client::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::client::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::client::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::client::MemberDescription* guildLeaderDescription = guildClub->add_leader();
87
88 guildLeaderDescription->mutable_id()->set_account_id(guildLeader->GetAccountId());
89 guildLeaderDescription->mutable_id()->set_unique_id(guildLeader->GetGUID().GetCounter());
90
91 club::v1::client::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::client::PRESENCE_LEVEL_RICH);
107 subscriber->set_whisper_level(club::v1::client::WHISPER_LEVEL_OPEN);
108
109 // Member is online and active.
110 subscriber->set_active(true);
111
112 WorldserverService<club::v1::client::ClubListener>(_session).OnSubscribe(&subscribeNotification, true, true);
113
114 // Notify the client about the changed club state.
115 club::v1::client::SubscriberStateChangedNotification subscriberStateChangedNotification;
116
117 subscriberStateChangedNotification.set_club_id(guild->GetId());
118
119 club::v1::client::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::client::ClubListener>(_session).OnSubscriberStateChanged(&subscriberStateChangedNotification, true, true);
127
128 return ERROR_OK;
129}
130
131uint32 ClubService::HandleGetMembers(club::v1::client::GetMembersRequest const* /*request*/, club::v1::client::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::client::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::client::PresenceLevel::PRESENCE_LEVEL_RICH);
162 clubMember->set_whisper_level(club::v1::client::WhisperLevel::WHISPER_LEVEL_OPEN);
163 std::string_view publicNote = member.GetPublicNote();
164 clubMember->set_note(publicNote.data(), publicNote.size());
165 clubMember->set_active(member.IsOnline());
166 }
167
168 return ERROR_OK;
169}
170
171uint32 ClubService::HandleGetStreams(club::v1::client::GetStreamsRequest const* /*request*/, club::v1::client::GetStreamsResponse* response,
172 std::function<void(ServiceBase*, uint32, google::protobuf::Message const*)>& /*continuation*/)
173{
174 Player const* player = _session->GetPlayer();
175
176 if (!player)
177 return ERROR_INTERNAL;
178
179 Guild const* guild = player->GetGuild();
180
181 if (!guild)
182 return ERROR_CLUB_NO_CLUB;
183
184 // General guild channel.
185 club::v1::client::Stream* generalGuildChannelStream = response->add_stream();
186
187 generalGuildChannelStream->set_club_id(guild->GetId());
188 generalGuildChannelStream->set_id(AsUnderlyingType(ClubStreamType::Guild));
189
190 v2::Attribute* generalStreamAttribute = generalGuildChannelStream->add_attribute();
191
192 generalStreamAttribute->set_name("global_strings_tag");
193 generalStreamAttribute->mutable_value()->set_string_value("COMMUNITIES_GUILD_GENERAL_CHANNEL_NAME");
194
195 generalGuildChannelStream->set_name("Guild");
196
197 // All roles got access to this channel.
198 // Club roles are currently guild role + 1.
199 // With a complete club/community system those will be handled differently.
200 generalGuildChannelStream->mutable_access()->add_role(AsUnderlyingType(ClubRoleIdentifier::Owner));
201 generalGuildChannelStream->mutable_access()->add_role(AsUnderlyingType(ClubRoleIdentifier::Leader));
202 generalGuildChannelStream->mutable_access()->add_role(AsUnderlyingType(ClubRoleIdentifier::Moderator));
203 generalGuildChannelStream->mutable_access()->add_role(AsUnderlyingType(ClubRoleIdentifier::Member));
204
205 // No voice support.
206 generalGuildChannelStream->set_voice_level(club::v1::client::StreamVoiceLevel::VOICE_LEVEL_DISABLED);
207
208 // Officer guild channel.
209 club::v1::client::Stream* officerGuildChannelStream = response->add_stream();
210
211 officerGuildChannelStream->set_club_id(guild->GetId());
212 officerGuildChannelStream->set_id(AsUnderlyingType(ClubStreamType::Officer));
213
214 v2::Attribute* officerStreamAttribute = officerGuildChannelStream->add_attribute();
215
216 officerStreamAttribute->set_name("global_strings_tag");
217 officerStreamAttribute->mutable_value()->set_string_value("COMMUNITIES_GUILD_OFFICER_CHANNEL_NAME");
218
219 officerGuildChannelStream->set_name("Officer");
220
221 // All roles got access to this channel.
222 // Club roles are currently guild role + 1.
223 // With a complete club/community system those will be handled differently.
224 officerGuildChannelStream->mutable_access()->add_role(AsUnderlyingType(ClubRoleIdentifier::Owner));
225 officerGuildChannelStream->mutable_access()->add_role(AsUnderlyingType(ClubRoleIdentifier::Leader));
226 officerGuildChannelStream->mutable_access()->add_role(AsUnderlyingType(ClubRoleIdentifier::Moderator));
227
228 // No voice support.
229 officerGuildChannelStream->set_voice_level(club::v1::client::StreamVoiceLevel::VOICE_LEVEL_DISABLED);
230
231 // Enable channel view
232 club::v1::client::StreamView* generalView = response->add_view();
233
234 generalView->set_club_id(guild->GetId());
235 generalView->set_stream_id(AsUnderlyingType(ClubStreamType::Guild));
236
237 club::v1::client::StreamView* officerView = response->add_view();
238
239 officerView->set_club_id(guild->GetId());
240 officerView->set_stream_id(AsUnderlyingType(ClubStreamType::Officer));
241
242 return ERROR_OK;
243}
244
245uint32 ClubService::HandleSubscribeStream(club::v1::client::SubscribeStreamRequest const* request, NoData* /*response*/,
246 std::function<void(ServiceBase*, uint32, google::protobuf::Message const*)>& /*continuation*/)
247{
248 Player const* player = _session->GetPlayer();
249
250 if (!player)
251 return ERROR_INTERNAL;
252
253 Guild const* guild = player->GetGuild();
254
255 if (!guild)
256 return ERROR_CLUB_NO_CLUB;
257
258 // Basic sanity check until full communities are implemented.
259 // 1 - Guild, 2 - Officer chat stream.
260 if (request->stream_id().empty() || (request->stream_id().Get(0) != AsUnderlyingType(ClubStreamType::Guild) && request->stream_id().Get(0) != AsUnderlyingType(ClubStreamType::Officer)))
262
263 return ERROR_OK;
264}
265
266uint32 ClubService::HandleUnsubscribeStream(club::v1::client::UnsubscribeStreamRequest const* /*request*/, NoData* /*response*/,
267 std::function<void(ServiceBase*, uint32, google::protobuf::Message const*)>& /*continuation*/)
268{
269 // We just have to signal the client that the unsubscribe request came through.
270 return ERROR_OK;
271}
272
273uint32 ClubService::HandleSetStreamFocus(club::v1::client::SetStreamFocusRequest const* /*request*/, NoData* /*response*/,
274 std::function<void(ServiceBase*, uint32, google::protobuf::Message const*)>& /*continuation*/)
275{
276 Player const* player = _session->GetPlayer();
277
278 if (!player)
279 return ERROR_INTERNAL;
280
281 Guild const* guild = player->GetGuild();
282
283 if (!guild)
285
286 return ERROR_OK;
287}
288
289uint32 ClubService::HandleAdvanceStreamViewTime(club::v1::client::AdvanceStreamViewTimeRequest const* /*request*/, NoData* /*response*/,
290 std::function<void(ServiceBase*, uint32, google::protobuf::Message const*)>& /*continuation*/)
291{
292 Player const* player = _session->GetPlayer();
293
294 if (!player)
295 return ERROR_INTERNAL;
296
297 Guild const* guild = player->GetGuild();
298
299 if (!guild)
301
302 return ERROR_OK;
303}
304
305uint32 ClubService::HandleCreateMessage(club::v1::client::CreateMessageRequest const* request, club::v1::client::CreateMessageResponse* response,
306 std::function<void(ServiceBase*, uint32, google::protobuf::Message const*)>& continuation)
307{
308 // Basic sanity check until full communities are implemented.
309 // 1 - Guild, 2 - Officer chat stream.
310 if (request->stream_id() != AsUnderlyingType(ClubStreamType::Guild) && request->stream_id() != AsUnderlyingType(ClubStreamType::Officer))
312
313 // Just some sanity checks. We do not care about the requested stream for now since we only have two.
314 Player const* player = _session->GetPlayer();
315
316 if (!player)
317 return ERROR_INTERNAL;
318
319 Guild const* guild = player->GetGuild();
320
321 if (!guild)
322 return ERROR_CLUB_NO_CLUB;
323
324 GuildRankRights requiredRights = { };
325 ChatMessageResult result = { };
326
327 switch (ClubStreamType(request->stream_id()))
328 {
330 requiredRights = GR_RIGHT_GCHATLISTEN;
331 result = _session->HandleChatMessage(CHAT_MSG_GUILD, LANG_UNIVERSAL, request->options().content());
332 break;
334 requiredRights = GR_RIGHT_OFFCHATLISTEN;
335 result = _session->HandleChatMessage(CHAT_MSG_OFFICER, LANG_UNIVERSAL, request->options().content());
336 break;
337 default:
339 }
340
341 if (result == ChatMessageResult::Ok)
342 {
343 std::chrono::microseconds messageTime = std::chrono::duration_cast<std::chrono::microseconds>(GameTime::GetSystemTime().time_since_epoch());
344
345 FillStreamMessage(response->mutable_message(), request->options().content(), messageTime, player->GetGUID());
346
347 club::v1::client::StreamMessageAddedNotification messageAddedNotification;
348 messageAddedNotification.set_allocated_agent_id(ClubMembershipService::CreateClubMemberId(player->GetGUID()).release());
349 messageAddedNotification.set_club_id(guild->GetId());
350 messageAddedNotification.set_stream_id(request->stream_id());
351 FillStreamMessage(messageAddedNotification.mutable_message(), request->options().content(), messageTime, player->GetGUID());
352
353 guild->BroadcastWorker([&](Player const* receiver)
354 {
355 Guild::Member const* receiverMember = guild->GetMember(receiver->GetGUID());
356 if (!guild->HasAnyRankRight(receiverMember->GetRankId(), requiredRights))
357 return;
358
359 if (receiver->GetSocial()->HasIgnore(player->GetGUID(), _session->GetAccountGUID()))
360 return;
361
362 WorldserverService<club::v1::client::ClubListener>(receiver->GetSession()).OnStreamMessageAdded(&messageAddedNotification, true, true);
363 }, player);
364
365 return ERROR_OK;
366 }
367
368 // If the message is empty there should never be a response to message request.
369 continuation = nullptr;
370
372}
373
374std::unique_ptr<club::v1::UniqueClubType> ClubService::CreateGuildClubType()
375{
376 std::unique_ptr<club::v1::UniqueClubType> type = std::make_unique<club::v1::UniqueClubType>();
377 type->set_program(5730135);
378 type->set_name("guild");
379 return type;
380}
381
382void ClubService::FillStreamMessage(club::v1::client::StreamMessage* message, std::string_view msg, std::chrono::microseconds messageTime, ObjectGuid author)
383{
384 message->mutable_id()->set_epoch(messageTime.count());
385 message->mutable_id()->set_position(0);
386
387 message->mutable_author()->set_allocated_id(ClubMembershipService::CreateClubMemberId(author).release());
388
389 club::v1::client::ContentChain* contentChain = message->add_content_chain();
390
391 contentChain->set_content(msg.data(), msg.size());
392 contentChain->set_edit_time(messageTime.count());
393}
394}
@ 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
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:1290
Guild * GetGuild()
Definition Player.cpp:30511
WorldSession * GetSession() const
Definition Player.h:2272
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={})
void set_content(const ::std::string &value)
SystemTimePoint GetSystemTime()
Current chrono system_clock time point.
Definition GameTime.cpp:62