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