TrinityCore
Channel.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 "Channel.h"
19#include "AccountMgr.h"
20#include "ChannelAppenders.h"
21#include "ChannelMgr.h"
22#include "Chat.h"
23#include "ChatPackets.h"
24#include "DB2Stores.h"
25#include "DatabaseEnv.h"
26#include "GameTime.h"
27#include "GridNotifiers.h"
28#include "GridNotifiersImpl.h"
29#include "Log.h"
30#include "ObjectAccessor.h"
31#include "Player.h"
32#include "SocialMgr.h"
33#include "StringConvert.h"
34#include "World.h"
35#include "WorldSession.h"
36#include <sstream>
37
38Channel::Channel(ObjectGuid const& guid, uint32 channelId, uint32 team /*= 0*/, AreaTableEntry const* zoneEntry /*= nullptr*/) :
39 _isDirty(false),
40 _nextActivityUpdateTime(0),
41 _announceEnabled(false), // no join/leave announces
42 _ownershipEnabled(false), // no ownership handout
43 _isOwnerInvisible(false),
44 _channelFlags(CHANNEL_FLAG_GENERAL), // for all built-in channels
45 _channelId(channelId),
46 _channelTeam(team),
47 _channelGuid(guid),
48 _zoneEntry(zoneEntry)
49{
50 ChatChannelsEntry const* channelEntry = sChatChannelsStore.AssertEntry(channelId);
51 if (channelEntry->GetFlags().HasFlag(ChatChannelFlags::AllowItemLinks)) // for trade channel
53
54 if (channelEntry->GetFlags().HasFlag(ChatChannelFlags::LinkedChannel)) // for city only channels
56
57 if (channelEntry->GetFlags().HasFlag(ChatChannelFlags::LookingForGroup)) // for LFG channel
59 else // for all other channels
61}
62
63Channel::Channel(ObjectGuid const& guid, std::string const& name, uint32 team /*= 0*/, std::string const& banList) :
64 _isDirty(false),
65 _nextActivityUpdateTime(0),
66 _announceEnabled(true),
67 _ownershipEnabled(true),
68 _isOwnerInvisible(false),
69 _channelFlags(CHANNEL_FLAG_CUSTOM),
70 _channelId(0),
71 _channelTeam(team),
72 _channelGuid(guid),
73 _channelName(name),
74 _zoneEntry(nullptr)
75{
76 for (std::string_view guid : Trinity::Tokenize(banList, ' ', false))
77 {
78 // legacy db content might not have 0x prefix, account for that
79 if (guid.size() > 2 && guid.substr(0, 2) == "0x")
80 guid.remove_suffix(2);
81
82 Optional<uint64> high = Trinity::StringTo<uint64>(guid.substr(0, 16), 16);
83 Optional<uint64> low = Trinity::StringTo<uint64>(guid.substr(16, 16), 16);
84 if (!high || !low)
85 continue;
86
87 ObjectGuid banned;
88 banned.SetRawValue(*high, *low);
89 if (!banned)
90 continue;
91
92 TC_LOG_DEBUG("chat.system", "Channel({}) loaded player {} into bannedStore", name, banned.ToString());
93 _bannedStore.insert(banned);
94 }
95}
96
97void Channel::GetChannelName(std::string& channelName, uint32 channelId, LocaleConstant locale, AreaTableEntry const* zoneEntry)
98{
99 if (channelId)
100 {
101 ChatChannelsEntry const* channelEntry = sChatChannelsStore.AssertEntry(channelId);
102 if (channelEntry->GetFlags().HasFlag(ChatChannelFlags::ZoneBased))
103 {
104 if (channelEntry->GetFlags().HasFlag(ChatChannelFlags::LinkedChannel))
106
107 channelName = fmt::sprintf(channelEntry->Name[locale], ASSERT_NOTNULL(zoneEntry)->AreaName[locale]);
108 }
109 else
110 channelName = channelEntry->Name[locale];
111 }
112}
113
114std::string Channel::GetName(LocaleConstant locale /*= DEFAULT_LOCALE*/) const
115{
116 std::string result = _channelName;
118
119 return result;
120}
121
123{
124 time_t const now = GameTime::GetGameTime();
125 if (_isDirty)
126 {
127 std::ostringstream banlist;
128 for (ObjectGuid const& guid : _bannedStore)
129 banlist << guid.ToHexString() << ' ';
130
132 stmt->setString(0, _channelName);
133 stmt->setUInt32(1, _channelTeam);
134 stmt->setBool(2, _announceEnabled);
135 stmt->setBool(3, _ownershipEnabled);
136 stmt->setString(4, _channelPassword);
137 stmt->setString(5, banlist.str());
138 CharacterDatabase.Execute(stmt);
139 }
140 else if (_nextActivityUpdateTime <= now)
141 {
142 if (!_playersStore.empty())
143 {
145 stmt->setString(0, _channelName);
146 stmt->setUInt32(1, _channelTeam);
147 CharacterDatabase.Execute(stmt);
148 }
149 }
150 else
151 return;
152
153 _isDirty = false;
154 _nextActivityUpdateTime = now + urand(1 * MINUTE, 6 * MINUTE) * std::max(1u, sWorld->getIntConfig(CONFIG_PRESERVE_CUSTOM_CHANNEL_INTERVAL));
155}
156
157void Channel::JoinChannel(Player* player, std::string const& pass)
158{
159 ObjectGuid const& guid = player->GetGUID();
160 if (IsOn(guid))
161 {
162 // Do not send error message for built-in channels
163 if (!IsConstant())
164 {
165 PlayerAlreadyMemberAppend appender(guid);
166 ChannelNameBuilder<PlayerAlreadyMemberAppend> builder(this, appender);
167 SendToOne(builder, guid);
168 }
169 return;
170 }
171
172 if (IsBanned(guid))
173 {
174 BannedAppend appender;
175 ChannelNameBuilder<BannedAppend> builder(this, appender);
176 SendToOne(builder, guid);
177 return;
178 }
179
180 if (!CheckPassword(pass))
181 {
182 WrongPasswordAppend appender;
183 ChannelNameBuilder<WrongPasswordAppend> builder(this, appender);
184 SendToOne(builder, guid);
185 return;
186 }
187
189 sWorld->getBoolConfig(CONFIG_RESTRICTED_LFG_CHANNEL) &&
190 AccountMgr::IsPlayerAccount(player->GetSession()->GetSecurity()) && //FIXME: Move to RBAC
191 player->GetGroup())
192 {
193 NotInLFGAppend appender;
194 ChannelNameBuilder<NotInLFGAppend> builder(this, appender);
195 SendToOne(builder, guid);
196 return;
197 }
198
199 player->JoinedChannel(this);
200
202 {
203 JoinedAppend appender(guid);
204 ChannelNameBuilder<JoinedAppend> builder(this, appender);
205 SendToAll(builder);
206 }
207
208 bool newChannel = _playersStore.empty();
209 if (newChannel)
210 _nextActivityUpdateTime = 0; // force activity update on next channel tick
211
212 PlayerInfo& playerInfo = _playersStore[guid];
213 playerInfo.SetInvisible(!player->isGMVisible());
214
215 /*
216 YouJoinedAppend appender;
217 ChannelNameBuilder<YouJoinedAppend> builder(this, appender);
218 SendToOne(builder, guid);
219 */
220
221 auto builder = [&](LocaleConstant locale)
222 {
223 LocaleConstant localeIdx = sWorld->GetAvailableDbcLocale(locale);
224
226 //notify->Data.ChannelWelcomeMsg = "";
227 notify->Data.ChatChannelID = _channelId;
228 //notify->Data.InstanceID = 0;
229 notify->Data._ChannelFlags = _channelFlags;
230 notify->Data._Channel = GetName(localeIdx);
231 notify->Data.ChannelGUID = _channelGuid;
232 notify->Data.Write();
233 return notify;
234 };
235
236 SendToOne(builder, guid);
237
238 JoinNotify(player);
239
240 // Custom channel handling
241 if (!IsConstant())
242 {
243 // If the channel has no owner yet and ownership is allowed, set the new owner.
244 // or if the owner was a GM with .gm visible off
245 // don't do this if the new player is, too, an invis GM, unless the channel was empty
246 if (_ownershipEnabled && (newChannel || !playerInfo.IsInvisible()) && (_ownerGuid.IsEmpty() || _isOwnerInvisible))
247 {
248 _isOwnerInvisible = playerInfo.IsInvisible();
249
250 SetOwner(guid, !newChannel && !_isOwnerInvisible);
251 playerInfo.SetModerator(true);
252 }
253 }
254}
255
256void Channel::LeaveChannel(Player* player, bool send, bool suspend)
257{
258 ObjectGuid const& guid = player->GetGUID();
259 if (!IsOn(guid))
260 {
261 if (send)
262 {
263 NotMemberAppend appender;
264 ChannelNameBuilder<NotMemberAppend> builder(this, appender);
265 SendToOne(builder, guid);
266 }
267 return;
268 }
269
270 player->LeftChannel(this);
271
272 if (send)
273 {
274 /*
275 YouLeftAppend appender;
276 ChannelNameBuilder<YouLeftAppend> builder(this, appender);
277 SendToOne(builder, guid);
278 */
279
280 auto builder = [&](LocaleConstant locale)
281 {
282 LocaleConstant localeIdx = sWorld->GetAvailableDbcLocale(locale);
283
285 notify->Data.Channel = GetName(localeIdx);
286 notify->Data.ChatChannelID = _channelId;
287 notify->Data.Suspended = suspend;
288 notify->Data.Write();
289 return notify;
290 };
291
292 SendToOne(builder, guid);
293 }
294
295 PlayerInfo& info = _playersStore.at(guid);
296 bool changeowner = info.IsOwner();
297 _playersStore.erase(guid);
298
300 {
301 LeftAppend appender(guid);
302 ChannelNameBuilder<LeftAppend> builder(this, appender);
303 SendToAll(builder);
304 }
305
306 LeaveNotify(player);
307
308 if (!IsConstant())
309 {
310 // If the channel owner left and there are still playersStore inside, pick a new owner
311 // do not pick invisible gm owner unless there are only invisible gms in that channel (rare)
312 if (changeowner && _ownershipEnabled && !_playersStore.empty())
313 {
314 PlayerContainer::iterator itr;
315 for (itr = _playersStore.begin(); itr != _playersStore.end(); ++itr)
316 {
317 if (!itr->second.IsInvisible())
318 break;
319 }
320
321 if (itr == _playersStore.end())
322 itr = _playersStore.begin();
323
324 ObjectGuid const& newowner = itr->first;
325 itr->second.SetModerator(true);
326
327 SetOwner(newowner);
328
329 // if the new owner is invisible gm, set flag to automatically choose a new owner
330 if (itr->second.IsInvisible())
331 _isOwnerInvisible = true;
332 }
333 }
334}
335
336void Channel::KickOrBan(Player const* player, std::string const& badname, bool ban)
337{
338 ObjectGuid const& good = player->GetGUID();
339
340 if (!IsOn(good))
341 {
342 NotMemberAppend appender;
343 ChannelNameBuilder<NotMemberAppend> builder(this, appender);
344 SendToOne(builder, good);
345 return;
346 }
347
348 PlayerInfo& info = _playersStore.at(good);
350 {
351 NotModeratorAppend appender;
352 ChannelNameBuilder<NotModeratorAppend> builder(this, appender);
353 SendToOne(builder, good);
354 return;
355 }
356
358 ObjectGuid const& victim = bad ? bad->GetGUID() : ObjectGuid::Empty;
359 if (!bad || !victim || !IsOn(victim))
360 {
361 PlayerNotFoundAppend appender(badname);
362 ChannelNameBuilder<PlayerNotFoundAppend> builder(this, appender);
363 SendToOne(builder, good);
364 return;
365 }
366
367 bool changeowner = _ownerGuid == victim;
368
369 if (!player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR) && changeowner && good != _ownerGuid)
370 {
371 NotOwnerAppend appender;
372 ChannelNameBuilder<NotOwnerAppend> builder(this, appender);
373 SendToOne(builder, good);
374 return;
375 }
376
377 if (ban && !IsBanned(victim))
378 {
379 _bannedStore.insert(victim);
380 _isDirty = true;
381
383 {
384 PlayerBannedAppend appender(good, victim);
385 ChannelNameBuilder<PlayerBannedAppend> builder(this, appender);
386 SendToAll(builder);
387 }
388 }
390 {
391 PlayerKickedAppend appender(good, victim);
392 ChannelNameBuilder<PlayerKickedAppend> builder(this, appender);
393 SendToAll(builder);
394 }
395
396 _playersStore.erase(victim);
397 bad->LeftChannel(this);
398
399 if (changeowner && _ownershipEnabled && !_playersStore.empty())
400 {
401 info.SetModerator(true);
402 SetOwner(good);
403 }
404}
405
406void Channel::UnBan(Player const* player, std::string const& badname)
407{
408 ObjectGuid const& good = player->GetGUID();
409
410 if (!IsOn(good))
411 {
412 NotMemberAppend appender;
413 ChannelNameBuilder<NotMemberAppend> builder(this, appender);
414 SendToOne(builder, good);
415 return;
416 }
417
418 PlayerInfo& info = _playersStore.at(good);
420 {
421 NotModeratorAppend appender;
422 ChannelNameBuilder<NotModeratorAppend> builder(this, appender);
423 SendToOne(builder, good);
424 return;
425 }
426
428 ObjectGuid victim = bad ? bad->GetGUID() : ObjectGuid::Empty;
429
430 if (victim.IsEmpty() || !IsBanned(victim))
431 {
432 PlayerNotFoundAppend appender(badname);
433 ChannelNameBuilder<PlayerNotFoundAppend> builder(this, appender);
434 SendToOne(builder, good);
435 return;
436 }
437
438 _bannedStore.erase(victim);
439
440 PlayerUnbannedAppend appender(good, victim);
441 ChannelNameBuilder<PlayerUnbannedAppend> builder(this, appender);
442 SendToAll(builder);
443
444 _isDirty = true;
445}
446
447void Channel::Password(Player const* player, std::string const& pass)
448{
449 ObjectGuid const& guid = player->GetGUID();
450
451 if (!IsOn(guid))
452 {
453 NotMemberAppend appender;
454 ChannelNameBuilder<NotMemberAppend> builder(this, appender);
455 SendToOne(builder, guid);
456 return;
457 }
458
459 PlayerInfo& info = _playersStore.at(guid);
461 {
462 NotModeratorAppend appender;
463 ChannelNameBuilder<NotModeratorAppend> builder(this, appender);
464 SendToOne(builder, guid);
465 return;
466 }
467
468 _channelPassword = pass;
469
470 PasswordChangedAppend appender(guid);
471 ChannelNameBuilder<PasswordChangedAppend> builder(this, appender);
472 SendToAll(builder);
473
474 _isDirty = true;
475}
476
477void Channel::SetMode(Player const* player, std::string const& p2n, bool mod, bool set)
478{
479 ObjectGuid const& guid = player->GetGUID();
480
481 if (!IsOn(guid))
482 {
483 NotMemberAppend appender;
484 ChannelNameBuilder<NotMemberAppend> builder(this, appender);
485 SendToOne(builder, guid);
486 return;
487 }
488
489 PlayerInfo& info = _playersStore.at(guid);
491 {
492 NotModeratorAppend appender;
493 ChannelNameBuilder<NotModeratorAppend> builder(this, appender);
494 SendToOne(builder, guid);
495 return;
496 }
497
498 if (guid == _ownerGuid && p2n == player->GetName() && mod)
499 return;
500
502 ObjectGuid victim = newp ? newp->GetGUID() : ObjectGuid::Empty;
503
504 if (!newp || victim.IsEmpty() || !IsOn(victim) ||
505 (player->GetTeam() != newp->GetTeam() &&
508 {
509 PlayerNotFoundAppend appender(p2n);
510 ChannelNameBuilder<PlayerNotFoundAppend> builder(this, appender);
511 SendToOne(builder, guid);
512 return;
513 }
514
515 if (_ownerGuid == victim && _ownerGuid != guid)
516 {
517 NotOwnerAppend appender;
518 ChannelNameBuilder<NotOwnerAppend> builder(this, appender);
519 SendToOne(builder, guid);
520 return;
521 }
522
523 if (mod)
524 SetModerator(newp->GetGUID(), set);
525 else
526 SetMute(newp->GetGUID(), set);
527}
528
529void Channel::SetInvisible(Player const* player, bool on)
530{
531 auto itr = _playersStore.find(player->GetGUID());
532 if (itr == _playersStore.end())
533 return;
534
535 itr->second.SetInvisible(on);
536
537 // we happen to be owner too, update flag
538 if (_ownerGuid == player->GetGUID())
540}
541
542void Channel::SetOwner(Player const* player, std::string const& newname)
543{
544 ObjectGuid const& guid = player->GetGUID();
545
546 if (!IsOn(guid))
547 {
548 NotMemberAppend appender;
549 ChannelNameBuilder<NotMemberAppend> builder(this, appender);
550 SendToOne(builder, guid);
551 return;
552 }
553
555 {
556 NotOwnerAppend appender;
557 ChannelNameBuilder<NotOwnerAppend> builder(this, appender);
558 SendToOne(builder, guid);
559 return;
560 }
561
563 ObjectGuid victim = newp ? newp->GetGUID() : ObjectGuid::Empty;
564
565 if (!newp || !victim || !IsOn(victim) ||
566 (player->GetTeam() != newp->GetTeam() &&
569 {
570 PlayerNotFoundAppend appender(newname);
571 ChannelNameBuilder<PlayerNotFoundAppend> builder(this, appender);
572 SendToOne(builder, guid);
573 return;
574 }
575
576 PlayerInfo& info = _playersStore.at(victim);
577 info.SetModerator(true);
578 SetOwner(victim);
579}
580
581void Channel::SendWhoOwner(Player const* player)
582{
583 ObjectGuid const& guid = player->GetGUID();
584 if (IsOn(guid))
585 {
586 ChannelOwnerAppend appender(this, _ownerGuid);
587 ChannelNameBuilder<ChannelOwnerAppend> builder(this, appender);
588 SendToOne(builder, guid);
589 }
590 else
591 {
592 NotMemberAppend appender;
593 ChannelNameBuilder<NotMemberAppend> builder(this, appender);
594 SendToOne(builder, guid);
595 }
596}
597
598void Channel::List(Player const* player)
599{
600 ObjectGuid const& guid = player->GetGUID();
601 if (!IsOn(guid))
602 {
603 NotMemberAppend appender;
604 ChannelNameBuilder<NotMemberAppend> builder(this, appender);
605 SendToOne(builder, guid);
606 return;
607 }
608
609 std::string channelName = GetName(player->GetSession()->GetSessionDbcLocale());
610 TC_LOG_DEBUG("chat.system", "SMSG_CHANNEL_LIST {} Channel: {}",
611 player->GetSession()->GetPlayerInfo(), channelName);
612
614 list._Display = true;
615 list._Channel = channelName;
616 list._ChannelFlags = GetFlags();
617
618 uint32 gmLevelInWhoList = sWorld->getIntConfig(CONFIG_GM_LEVEL_IN_WHO_LIST);
619
620 list._Members.reserve(_playersStore.size());
621 for (PlayerContainer::value_type const& i : _playersStore)
622 {
624
625 // PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters
626 // MODERATOR, GAME MASTER, ADMINISTRATOR can see all
627 if (member &&
629 member->GetSession()->GetSecurity() <= AccountTypes(gmLevelInWhoList)) &&
630 member->IsVisibleGloballyFor(player))
631 {
632 list._Members.emplace_back(i.first, GetVirtualRealmAddress(), i.second.GetFlags());
633 }
634 }
635
636 player->SendDirectMessage(list.Write());
637}
638
639void Channel::Announce(Player const* player)
640{
641 ObjectGuid const& guid = player->GetGUID();
642
643 if (!IsOn(guid))
644 {
645 NotMemberAppend appender;
646 ChannelNameBuilder<NotMemberAppend> builder(this, appender);
647 SendToOne(builder, guid);
648 return;
649 }
650
651 PlayerInfo const& playerInfo = _playersStore.at(guid);
653 {
654 NotModeratorAppend appender;
655 ChannelNameBuilder<NotModeratorAppend> builder(this, appender);
656 SendToOne(builder, guid);
657 return;
658 }
659
661
664 {
665 AnnouncementsOnAppend appender(guid);
666 ChannelNameBuilder<AnnouncementsOnAppend> builder(this, appender);
667 SendToAll(builder);
668 }
669 else
670 {
671 AnnouncementsOffAppend appender(guid);
672 ChannelNameBuilder<AnnouncementsOffAppend> builder(this, appender);
673 SendToAll(builder);
674 }
675
676 _isDirty = true;
677}
678
679void Channel::Say(ObjectGuid const& guid, std::string const& what, uint32 lang) const
680{
681 if (what.empty())
682 return;
683
684 // TODO: Add proper RBAC check
686 lang = LANG_UNIVERSAL;
687
688 if (!IsOn(guid))
689 {
690 NotMemberAppend appender;
691 ChannelNameBuilder<NotMemberAppend> builder(this, appender);
692 SendToOne(builder, guid);
693 return;
694 }
695
696 PlayerInfo const& playerInfo = _playersStore.at(guid);
697 if (playerInfo.IsMuted())
698 {
699 MutedAppend appender;
700 ChannelNameBuilder<MutedAppend> builder(this, appender);
701 SendToOne(builder, guid);
702 return;
703 }
704
706
707 auto builder = [&](LocaleConstant locale)
708 {
709 LocaleConstant localeIdx = sWorld->GetAvailableDbcLocale(locale);
710
712 packet->Data.ChannelGUID = _channelGuid;
713 if (player)
714 packet->Data.Initialize(CHAT_MSG_CHANNEL, Language(lang), player, player, what, 0, GetName(localeIdx));
715 else
716 {
717 packet->Data.Initialize(CHAT_MSG_CHANNEL, Language(lang), nullptr, nullptr, what, 0, GetName(localeIdx));
718 packet->Data.SenderGUID = guid;
719 packet->Data.TargetGUID = guid;
720 }
721
722 packet->Data.Write();
723
724 return packet;
725 };
726
727 SendToAll(builder, !playerInfo.IsModerator() ? guid : ObjectGuid::Empty,
728 !playerInfo.IsModerator() && player ? player->GetSession()->GetAccountGUID() : ObjectGuid::Empty);
729}
730
731void Channel::AddonSay(ObjectGuid const& guid, std::string const& prefix, std::string const& what, bool isLogged) const
732{
733 if (what.empty())
734 return;
735
736 if (!IsOn(guid))
737 {
738 NotMemberAppend appender;
739 ChannelNameBuilder<NotMemberAppend> builder(this, appender);
740 SendToOne(builder, guid);
741 return;
742 }
743
744 PlayerInfo const& playerInfo = _playersStore.at(guid);
745 if (playerInfo.IsMuted())
746 {
747 MutedAppend appender;
748 ChannelNameBuilder<MutedAppend> builder(this, appender);
749 SendToOne(builder, guid);
750 return;
751 }
752
754
755 auto builder = [&](LocaleConstant locale)
756 {
757 LocaleConstant localeIdx = sWorld->GetAvailableDbcLocale(locale);
758
760 packet->Data.ChannelGUID = _channelGuid;
761 if (player)
762 packet->Data.Initialize(CHAT_MSG_CHANNEL, isLogged ? LANG_ADDON_LOGGED : LANG_ADDON, player, player, what, 0, GetName(localeIdx), DEFAULT_LOCALE, prefix);
763 else
764 {
765 packet->Data.Initialize(CHAT_MSG_CHANNEL, isLogged ? LANG_ADDON_LOGGED : LANG_ADDON, nullptr, nullptr, what, 0, GetName(localeIdx), DEFAULT_LOCALE, prefix);
766 packet->Data.SenderGUID = guid;
767 packet->Data.TargetGUID = guid;
768 }
769
770 packet->Data.Write();
771
772 return packet;
773 };
774
775 SendToAllWithAddon(builder, prefix, !playerInfo.IsModerator() ? guid : ObjectGuid::Empty,
776 !playerInfo.IsModerator() && player ? player->GetSession()->GetAccountGUID() : ObjectGuid::Empty);
777}
778
779void Channel::Invite(Player const* player, std::string const& newname)
780{
781 ObjectGuid const& guid = player->GetGUID();
782
783 if (!IsOn(guid))
784 {
785 NotMemberAppend appender;
786 ChannelNameBuilder<NotMemberAppend> builder(this, appender);
787 SendToOne(builder, guid);
788 return;
789 }
790
792 if (!newp || !newp->isGMVisible())
793 {
794 PlayerNotFoundAppend appender(newname);
795 ChannelNameBuilder<PlayerNotFoundAppend> builder(this, appender);
796 SendToOne(builder, guid);
797 return;
798 }
799
800 if (IsBanned(newp->GetGUID()))
801 {
802 PlayerInviteBannedAppend appender(newname);
803 ChannelNameBuilder<PlayerInviteBannedAppend> builder(this, appender);
804 SendToOne(builder, guid);
805 return;
806 }
807
808 if (newp->GetTeam() != player->GetTeam() &&
811 {
813 ChannelNameBuilder<InviteWrongFactionAppend> builder(this, appender);
814 SendToOne(builder, guid);
815 return;
816 }
817
818 if (IsOn(newp->GetGUID()))
819 {
820 PlayerAlreadyMemberAppend appender(newp->GetGUID());
821 ChannelNameBuilder<PlayerAlreadyMemberAppend> builder(this, appender);
822 SendToOne(builder, guid);
823 return;
824 }
825
826 if (!newp->GetSocial()->HasIgnore(guid, player->GetSession()->GetAccountGUID()))
827 {
828 InviteAppend appender(guid);
829 ChannelNameBuilder<InviteAppend> builder(this, appender);
830 SendToOne(builder, newp->GetGUID());
831 }
832
833 PlayerInvitedAppend appender(newp->GetName());
834 ChannelNameBuilder<PlayerInvitedAppend> builder(this, appender);
835 SendToOne(builder, guid);
836}
837
838void Channel::SetOwner(ObjectGuid const& guid, bool exclaim)
839{
840 if (!_ownerGuid.IsEmpty())
841 {
842 // [] will re-add player after it possible removed
843 auto itr = _playersStore.find(_ownerGuid);
844 if (itr != _playersStore.end())
845 itr->second.SetOwner(false);
846 }
847
848 _ownerGuid = guid;
849 if (!_ownerGuid.IsEmpty())
850 {
852 auto itr = _playersStore.find(_ownerGuid);
853 if (itr == _playersStore.end())
854 return;
855
856 itr->second.SetModerator(true);
857 itr->second.SetOwner(true);
858
860 ChannelNameBuilder<ModeChangeAppend> builder(this, appender);
861 SendToAll(builder);
862
863 if (exclaim)
864 {
865 OwnerChangedAppend ownerAppender(_ownerGuid);
866 ChannelNameBuilder<OwnerChangedAppend> ownerBuilder(this, ownerAppender);
867 SendToAll(ownerBuilder);
868 }
869
870 _isDirty = true;
871 }
872}
873
874void Channel::SilenceAll(Player const* /*player*/, std::string const& /*name*/)
875{
876}
877
878void Channel::UnsilenceAll(Player const* /*player*/, std::string const& /*name*/)
879{
880}
881
882void Channel::DeclineInvite(Player const* /*player*/)
883{
884}
885
886void Channel::JoinNotify(Player const* player)
887{
888 ObjectGuid const& guid = player->GetGUID();
889
890 if (IsConstant())
891 {
892 auto builder = [&](LocaleConstant locale)
893 {
894 LocaleConstant localeIdx = sWorld->GetAvailableDbcLocale(locale);
895
897 userlistAdd->Data.AddedUserGUID = guid;
898 userlistAdd->Data._ChannelFlags = GetFlags();
899 userlistAdd->Data.UserFlags = GetPlayerFlags(guid);
900 userlistAdd->Data.ChannelID = GetChannelId();
901 userlistAdd->Data.ChannelName = GetName(localeIdx);
902 userlistAdd->Data.Write();
903 return userlistAdd;
904 };
905
906 SendToAllButOne(builder, guid);
907 }
908 else
909 {
910 auto builder = [&](LocaleConstant locale)
911 {
912 LocaleConstant localeIdx = sWorld->GetAvailableDbcLocale(locale);
913
915 userlistUpdate->Data.UpdatedUserGUID = guid;
916 userlistUpdate->Data._ChannelFlags = GetFlags();
917 userlistUpdate->Data.UserFlags = GetPlayerFlags(guid);
918 userlistUpdate->Data.ChannelID = GetChannelId();
919 userlistUpdate->Data.ChannelName = GetName(localeIdx);
920 userlistUpdate->Data.Write();
921 return userlistUpdate;
922 };
923
924 SendToAll(builder);
925 }
926}
927
928void Channel::LeaveNotify(Player const* player)
929{
930 ObjectGuid const& guid = player->GetGUID();
931
932 auto builder = [&](LocaleConstant locale)
933 {
934 LocaleConstant localeIdx = sWorld->GetAvailableDbcLocale(locale);
935
937 userlistRemove->Data.RemovedUserGUID = guid;
938 userlistRemove->Data._ChannelFlags = GetFlags();
939 userlistRemove->Data.ChannelID = GetChannelId();
940 userlistRemove->Data.ChannelName = GetName(localeIdx);
941 userlistRemove->Data.Write();
942 return userlistRemove;
943 };
944
945 if (IsConstant())
946 SendToAllButOne(builder, guid);
947 else
948 SendToAll(builder);
949}
950
951void Channel::SetModerator(ObjectGuid const& guid, bool set)
952{
953 if (!IsOn(guid))
954 return;
955
956 PlayerInfo& playerInfo = _playersStore.at(guid);
957 if (playerInfo.IsModerator() != set)
958 {
959 uint8 oldFlag = playerInfo.GetFlags();
960 playerInfo.SetModerator(set);
961
962 ModeChangeAppend appender(guid, oldFlag, playerInfo.GetFlags());
963 ChannelNameBuilder<ModeChangeAppend> builder(this, appender);
964 SendToAll(builder);
965 }
966}
967
968void Channel::SetMute(ObjectGuid const& guid, bool set)
969{
970 if (!IsOn(guid))
971 return;
972
973 PlayerInfo& playerInfo = _playersStore.at(guid);
974 if (playerInfo.IsMuted() != set)
975 {
976 uint8 oldFlag = playerInfo.GetFlags();
977 playerInfo.SetMuted(set);
978
979 ModeChangeAppend appender(guid, oldFlag, playerInfo.GetFlags());
980 ChannelNameBuilder<ModeChangeAppend> builder(this, appender);
981 SendToAll(builder);
982 }
983}
984
985template <class Builder>
986void Channel::SendToAll(Builder& builder, ObjectGuid const& guid, ObjectGuid const& accountGuid) const
987{
988 Trinity::LocalizedDo<Builder> localizer(builder);
989
990 for (PlayerContainer::value_type const& i : _playersStore)
991 if (Player* player = ObjectAccessor::FindConnectedPlayer(i.first))
992 if (guid.IsEmpty() || !player->GetSocial()->HasIgnore(guid, accountGuid))
993 localizer(player);
994}
995
996template <class Builder>
997void Channel::SendToAllButOne(Builder& builder, ObjectGuid const& who) const
998{
999 Trinity::LocalizedDo<Builder> localizer(builder);
1000
1001 for (PlayerContainer::value_type const& i : _playersStore)
1002 if (i.first != who)
1003 if (Player* player = ObjectAccessor::FindConnectedPlayer(i.first))
1004 localizer(player);
1005}
1006
1007template <class Builder>
1008void Channel::SendToOne(Builder& builder, ObjectGuid const& who) const
1009{
1010 Trinity::LocalizedDo<Builder> localizer(builder);
1011
1013 localizer(player);
1014}
1015
1016template <class Builder>
1017void Channel::SendToAllWithAddon(Builder& builder, std::string const& addonPrefix, ObjectGuid const& guid /*= ObjectGuid::Empty*/,
1018 ObjectGuid const& accountGuid /*= ObjectGuid::Empty*/) const
1019{
1020 Trinity::LocalizedDo<Builder> localizer(builder);
1021
1022 for (PlayerContainer::value_type const& i : _playersStore)
1023 if (Player* player = ObjectAccessor::FindConnectedPlayer(i.first))
1024 if (player->GetSession()->IsAddonRegistered(addonPrefix) && (guid.IsEmpty() || !player->GetSocial()->HasIgnore(guid, accountGuid)))
1025 localizer(player);
1026}
@ CHANNEL_FLAG_TRADE
Definition: Channel.h:88
@ CHANNEL_FLAG_NOT_LFG
Definition: Channel.h:89
@ CHANNEL_FLAG_GENERAL
Definition: Channel.h:90
@ CHANNEL_FLAG_CUSTOM
Definition: Channel.h:86
@ CHANNEL_FLAG_LFG
Definition: Channel.h:92
@ CHANNEL_FLAG_CITY
Definition: Channel.h:91
@ CHAR_UPD_CHANNEL
@ CHAR_UPD_CHANNEL_USAGE
LocaleConstant
Definition: Common.h:48
#define DEFAULT_LOCALE
Definition: Common.h:66
@ MINUTE
Definition: Common.h:29
AccountTypes
Definition: Common.h:39
DB2Storage< ChatChannelsEntry > sChatChannelsStore("ChatChannels.db2", &ChatChannelsLoadInfo::Instance)
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
Definition: DatabaseEnv.cpp:21
uint8_t uint8
Definition: Define.h:144
uint32_t uint32
Definition: Define.h:142
#define ASSERT_NOTNULL(pointer)
Definition: Errors.h:84
#define TC_LOG_DEBUG(filterType__,...)
Definition: Log.h:156
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
uint32 urand(uint32 min, uint32 max)
Definition: Random.cpp:42
Language
@ LANG_ADDON_LOGGED
@ LANG_UNIVERSAL
@ LANG_ADDON
@ CHAT_MSG_CHANNEL
static bool IsPlayerAccount(uint32 gmlevel)
Definition: AccountMgr.cpp:431
static AreaTableEntry const * SpecialLinkedArea
Definition: ChannelMgr.h:48
bool IsConstant() const
Definition: Channel.h:167
void Password(Player const *player, std::string const &pass)
Definition: Channel.cpp:447
void List(Player const *player)
Definition: Channel.cpp:598
uint32 _channelId
Definition: Channel.h:259
BannedContainer _bannedStore
Definition: Channel.h:266
void JoinChannel(Player *player, std::string const &pass="")
Definition: Channel.cpp:157
std::string GetName(LocaleConstant locale=DEFAULT_LOCALE) const
Definition: Channel.cpp:114
void SendToAllWithAddon(Builder &builder, std::string const &addonPrefix, ObjectGuid const &guid=ObjectGuid::Empty, ObjectGuid const &accountGuid=ObjectGuid::Empty) const
Definition: Channel.cpp:1017
bool _ownershipEnabled
Definition: Channel.h:255
bool _announceEnabled
Definition: Channel.h:254
void SendToOne(Builder &builder, ObjectGuid const &who) const
Definition: Channel.cpp:1008
bool HasFlag(uint8 flag) const
Definition: Channel.h:186
uint32 _channelTeam
Definition: Channel.h:260
void SendToAllButOne(Builder &builder, ObjectGuid const &who) const
Definition: Channel.cpp:997
Channel(ObjectGuid const &guid, uint32 channelId, uint32 team=0, AreaTableEntry const *zoneEntry=nullptr)
Definition: Channel.cpp:38
time_t _nextActivityUpdateTime
Definition: Channel.h:252
uint8 _channelFlags
Definition: Channel.h:258
std::string _channelName
Definition: Channel.h:263
void SetMute(Player const *player, std::string const &newname)
Definition: Channel.h:209
void SetModerator(Player const *player, std::string const &newname)
Definition: Channel.h:207
void KickOrBan(Player const *player, std::string const &badname, bool ban)
Definition: Channel.cpp:336
bool _isOwnerInvisible
Definition: Channel.h:256
uint32 GetChannelId() const
Definition: Channel.h:166
void SendWhoOwner(Player const *player)
Definition: Channel.cpp:581
ObjectGuid _channelGuid
Definition: Channel.h:261
bool CheckPassword(std::string const &password) const
Definition: Channel.h:181
bool IsOn(ObjectGuid who) const
Definition: Channel.h:236
void UnsilenceAll(Player const *player, std::string const &name)
Definition: Channel.cpp:878
void AddonSay(ObjectGuid const &guid, std::string const &prefix, std::string const &what, bool isLogged) const
Definition: Channel.cpp:731
void SetOwner(ObjectGuid const &guid, bool exclaim=true)
Definition: Channel.cpp:838
void UnBan(Player const *player, std::string const &badname)
Definition: Channel.cpp:406
void SilenceAll(Player const *player, std::string const &name)
Definition: Channel.cpp:874
uint8 GetPlayerFlags(ObjectGuid const &guid) const
Definition: Channel.h:239
bool _isDirty
Definition: Channel.h:251
void SetMode(Player const *player, std::string const &p2n, bool mod, bool set)
Definition: Channel.cpp:477
void Say(ObjectGuid const &guid, std::string const &what, uint32 lang) const
Definition: Channel.cpp:679
static void GetChannelName(std::string &channelName, uint32 channelId, LocaleConstant locale, AreaTableEntry const *zoneEntry)
Definition: Channel.cpp:97
void DeclineInvite(Player const *player)
Definition: Channel.cpp:882
void SetInvisible(Player const *player, bool on)
Definition: Channel.cpp:529
void UpdateChannelInDB()
Definition: Channel.cpp:122
void Announce(Player const *player)
Definition: Channel.cpp:639
void JoinNotify(Player const *player)
Definition: Channel.cpp:886
void Invite(Player const *player, std::string const &newp)
Definition: Channel.cpp:779
bool IsBanned(ObjectGuid guid) const
Definition: Channel.h:237
void SendToAll(Builder &builder, ObjectGuid const &guid=ObjectGuid::Empty, ObjectGuid const &accountGuid=ObjectGuid::Empty) const
Definition: Channel.cpp:986
AreaTableEntry const * _zoneEntry
Definition: Channel.h:268
ObjectGuid _ownerGuid
Definition: Channel.h:262
void LeaveNotify(Player const *player)
Definition: Channel.cpp:928
std::string _channelPassword
Definition: Channel.h:264
void LeaveChannel(Player *player, bool send=true, bool suspend=false)
Definition: Channel.cpp:256
uint8 GetFlags() const
Definition: Channel.h:185
PlayerContainer _playersStore
Definition: Channel.h:265
static ObjectGuid const Empty
Definition: ObjectGuid.h:274
bool IsEmpty() const
Definition: ObjectGuid.h:319
std::string ToString() const
Definition: ObjectGuid.cpp:554
void SetRawValue(std::vector< uint8 > const &guid)
Definition: ObjectGuid.cpp:584
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
bool HasIgnore(ObjectGuid const &ignoreGuid, ObjectGuid const &ignoreAccountGuid)
Definition: SocialMgr.cpp:189
bool isGMVisible() const
Definition: Player.h:1186
PlayerSocial * GetSocial() const
Definition: Player.h:1163
void SendDirectMessage(WorldPacket const *data) const
Definition: Player.cpp:6324
WorldSession * GetSession() const
Definition: Player.h:2101
bool IsVisibleGloballyFor(Player const *player) const
Definition: Player.cpp:23778
Group * GetGroup(Optional< uint8 > partyIndex)
Definition: Player.h:2606
void LeftChannel(Channel *c)
Definition: Player.cpp:4905
void JoinedChannel(Channel *c)
Definition: Player.cpp:4900
Team GetTeam() const
Definition: Player.h:2235
void setBool(const uint8 index, const bool value)
void setUInt32(const uint8 index, const uint32 value)
void setString(const uint8 index, const std::string &value)
std::string const & GetName() const
Definition: Object.h:555
std::vector< ChannelPlayer > _Members
WorldPacket const * Write() override
AccountTypes GetSecurity() const
Definition: WorldSession.h:999
ObjectGuid GetAccountGUID() const
LocaleConstant GetSessionDbcLocale() const
std::string GetPlayerInfo() const
bool HasPermission(uint32 permissionId)
#define sWorld
Definition: World.h:931
uint32 GetVirtualRealmAddress()
Definition: World.cpp:3968
@ CONFIG_PRESERVE_CUSTOM_CHANNEL_INTERVAL
Definition: World.h:379
@ CONFIG_GM_LEVEL_IN_WHO_LIST
Definition: World.h:292
@ CONFIG_RESTRICTED_LFG_CHANNEL
Definition: World.h:128
@ CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL
Definition: World.h:110
time_t GetGameTime()
Definition: GameTime.cpp:44
TC_GAME_API Player * FindConnectedPlayerByName(std::string_view name)
TC_GAME_API Player * FindConnectedPlayer(ObjectGuid const &)
TC_COMMON_API std::vector< std::string_view > Tokenize(std::string_view str, char sep, bool keepEmpty)
Definition: Util.cpp:56
@ RBAC_PERM_SILENTLY_JOIN_CHANNEL
Definition: RBAC.h:98
@ RBAC_PERM_WHO_SEE_ALL_SEC_LEVELS
Definition: RBAC.h:88
@ RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR
Definition: RBAC.h:99
@ RBAC_PERM_TWO_SIDE_INTERACTION_CHANNEL
Definition: RBAC.h:79
void SetModerator(bool state)
Definition: Channel.h:137
bool IsOwner() const
Definition: Channel.h:127
uint8 GetFlags() const
Definition: Channel.h:118
bool IsMuted() const
Definition: Channel.h:145
bool IsInvisible() const
Definition: Channel.h:120
void SetInvisible(bool on)
Definition: Channel.h:121
void SetMuted(bool state)
Definition: Channel.h:146
bool IsModerator() const
Definition: Channel.h:136
LocalizedString Name
Definition: DB2Structure.h:615
EnumFlag< ChatChannelFlags > GetFlags() const
Definition: DB2Structure.h:621