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 auto builder = [&](LocaleConstant locale)
218 {
219 LocaleConstant localeIdx = sWorld->GetAvailableDbcLocale(locale);
220
222 //notify->Data.ChannelWelcomeMsg = "";
223 notify->Data.ChatChannelID = _channelId;
224 //notify->Data.InstanceID = 0;
225 notify->Data._ChannelFlags = _channelFlags;
226 notify->Data.UserFlags = GetPlayerFlags(guid);
227 notify->Data._Channel = GetName(localeIdx);
228 notify->Data.ChannelGUID = _channelGuid;
229 notify->Data.Write();
230 return notify;
231 };
232
233 SendToOne(builder, guid);
234
235 JoinNotify(guid);
236
237 // Custom channel handling
238 if (!IsConstant())
239 {
240 // If the channel has no owner yet and ownership is allowed, set the new owner.
241 // or if the owner was a GM with .gm visible off
242 // don't do this if the new player is, too, an invis GM, unless the channel was empty
243 if (_ownershipEnabled && (newChannel || !playerInfo.IsInvisible()) && (_ownerGuid.IsEmpty() || _isOwnerInvisible))
244 {
245 _isOwnerInvisible = playerInfo.IsInvisible();
246
247 SetOwner(guid, !newChannel && !_isOwnerInvisible);
248 playerInfo.SetModerator(true);
249 }
250 }
251}
252
253void Channel::LeaveChannel(Player* player, bool send, bool suspend)
254{
255 ObjectGuid const& guid = player->GetGUID();
256 if (!IsOn(guid))
257 {
258 if (send)
259 {
260 NotMemberAppend appender;
261 ChannelNameBuilder<NotMemberAppend> builder(this, appender);
262 SendToOne(builder, guid);
263 }
264 return;
265 }
266
267 if (send)
268 {
269 auto builder = [&](LocaleConstant locale)
270 {
271 LocaleConstant localeIdx = sWorld->GetAvailableDbcLocale(locale);
272
274 notify->Data.Channel = GetName(localeIdx);
275 notify->Data.ChatChannelID = _channelId;
276 notify->Data.Suspended = suspend;
277 notify->Data.Write();
278 return notify;
279 };
280
281 SendToOne(builder, guid);
282
283 player->LeftChannel(this);
284 }
285
286 PlayerInfo info = _playersStore.extract(guid).mapped();
287 bool changeowner = info.IsOwner();
288
290 {
291 LeftAppend appender(guid);
292 ChannelNameBuilder<LeftAppend> builder(this, appender);
293 SendToAll(builder);
294 }
295
296 LeaveNotify(guid);
297
298 if (!IsConstant())
299 {
300 // If the channel owner left and there are players still inside, pick a new owner
301 // do not pick invisible gm owner unless there are only invisible gms in that channel (rare)
302 if (changeowner && _ownershipEnabled && !_playersStore.empty())
303 {
304 PlayerContainer::iterator itr;
305 for (itr = _playersStore.begin(); itr != _playersStore.end(); ++itr)
306 {
307 if (!itr->second.IsInvisible())
308 break;
309 }
310
311 if (itr == _playersStore.end())
312 itr = _playersStore.begin();
313
314 ObjectGuid const& newOwner = itr->first;
315 itr->second.SetModerator(true);
316
317 SetOwner(newOwner);
318
319 // if the new owner is invisible gm, set flag to automatically choose a new owner
320 if (itr->second.IsInvisible())
321 _isOwnerInvisible = true;
322 }
323 }
324}
325
326void Channel::KickOrBan(Player const* player, std::string const& badname, bool ban)
327{
328 ObjectGuid const& good = player->GetGUID();
329
330 if (!IsOn(good))
331 {
332 NotMemberAppend appender;
333 ChannelNameBuilder<NotMemberAppend> builder(this, appender);
334 SendToOne(builder, good);
335 return;
336 }
337
338 PlayerInfo& info = _playersStore.at(good);
340 {
341 NotModeratorAppend appender;
342 ChannelNameBuilder<NotModeratorAppend> builder(this, appender);
343 SendToOne(builder, good);
344 return;
345 }
346
348 ObjectGuid const& victim = bad ? bad->GetGUID() : ObjectGuid::Empty;
349 if (!bad || !victim || !IsOn(victim))
350 {
351 PlayerNotFoundAppend appender(badname);
352 ChannelNameBuilder<PlayerNotFoundAppend> builder(this, appender);
353 SendToOne(builder, good);
354 return;
355 }
356
357 bool changeowner = _ownerGuid == victim;
358
359 if (!player->GetSession()->HasPermission(rbac::RBAC_PERM_CHANGE_CHANNEL_NOT_MODERATOR) && changeowner && good != _ownerGuid)
360 {
361 NotOwnerAppend appender;
362 ChannelNameBuilder<NotOwnerAppend> builder(this, appender);
363 SendToOne(builder, good);
364 return;
365 }
366
367 if (ban && !IsBanned(victim))
368 {
369 _bannedStore.insert(victim);
370 _isDirty = true;
371
373 {
374 PlayerBannedAppend appender(good, victim);
375 ChannelNameBuilder<PlayerBannedAppend> builder(this, appender);
376 SendToAll(builder);
377 }
378 }
380 {
381 PlayerKickedAppend appender(good, victim);
382 ChannelNameBuilder<PlayerKickedAppend> builder(this, appender);
383 SendToAll(builder);
384 }
385
386 _playersStore.erase(victim);
387 bad->LeftChannel(this);
388
389 if (changeowner && _ownershipEnabled && !_playersStore.empty())
390 {
391 info.SetModerator(true);
392 SetOwner(good);
393 }
394}
395
396void Channel::UnBan(Player const* player, std::string const& badname)
397{
398 ObjectGuid const& good = player->GetGUID();
399
400 if (!IsOn(good))
401 {
402 NotMemberAppend appender;
403 ChannelNameBuilder<NotMemberAppend> builder(this, appender);
404 SendToOne(builder, good);
405 return;
406 }
407
408 PlayerInfo& info = _playersStore.at(good);
410 {
411 NotModeratorAppend appender;
412 ChannelNameBuilder<NotModeratorAppend> builder(this, appender);
413 SendToOne(builder, good);
414 return;
415 }
416
418 ObjectGuid victim = bad ? bad->GetGUID() : ObjectGuid::Empty;
419
420 if (victim.IsEmpty() || !IsBanned(victim))
421 {
422 PlayerNotFoundAppend appender(badname);
423 ChannelNameBuilder<PlayerNotFoundAppend> builder(this, appender);
424 SendToOne(builder, good);
425 return;
426 }
427
428 _bannedStore.erase(victim);
429
430 PlayerUnbannedAppend appender(good, victim);
431 ChannelNameBuilder<PlayerUnbannedAppend> builder(this, appender);
432 SendToAll(builder);
433
434 _isDirty = true;
435}
436
437void Channel::Password(Player const* player, std::string const& pass)
438{
439 ObjectGuid const& guid = player->GetGUID();
440
441 if (!IsOn(guid))
442 {
443 NotMemberAppend appender;
444 ChannelNameBuilder<NotMemberAppend> builder(this, appender);
445 SendToOne(builder, guid);
446 return;
447 }
448
449 PlayerInfo& info = _playersStore.at(guid);
451 {
452 NotModeratorAppend appender;
453 ChannelNameBuilder<NotModeratorAppend> builder(this, appender);
454 SendToOne(builder, guid);
455 return;
456 }
457
458 _channelPassword = pass;
459
460 PasswordChangedAppend appender(guid);
461 ChannelNameBuilder<PasswordChangedAppend> builder(this, appender);
462 SendToAll(builder);
463
464 _isDirty = true;
465}
466
467void Channel::SetMode(Player const* player, std::string const& p2n, bool mod, bool set)
468{
469 ObjectGuid const& guid = player->GetGUID();
470
471 if (!IsOn(guid))
472 {
473 NotMemberAppend appender;
474 ChannelNameBuilder<NotMemberAppend> builder(this, appender);
475 SendToOne(builder, guid);
476 return;
477 }
478
479 PlayerInfo& info = _playersStore.at(guid);
481 {
482 NotModeratorAppend appender;
483 ChannelNameBuilder<NotModeratorAppend> builder(this, appender);
484 SendToOne(builder, guid);
485 return;
486 }
487
488 if (guid == _ownerGuid && p2n == player->GetName() && mod)
489 return;
490
492 ObjectGuid victim = newp ? newp->GetGUID() : ObjectGuid::Empty;
493
494 if (!newp || victim.IsEmpty() || !IsOn(victim) ||
495 (player->GetTeam() != newp->GetTeam() &&
498 {
499 PlayerNotFoundAppend appender(p2n);
500 ChannelNameBuilder<PlayerNotFoundAppend> builder(this, appender);
501 SendToOne(builder, guid);
502 return;
503 }
504
505 if (_ownerGuid == victim && _ownerGuid != guid)
506 {
507 NotOwnerAppend appender;
508 ChannelNameBuilder<NotOwnerAppend> builder(this, appender);
509 SendToOne(builder, guid);
510 return;
511 }
512
513 if (mod)
514 SetModerator(newp->GetGUID(), set);
515 else
516 SetMute(newp->GetGUID(), set);
517}
518
519void Channel::SetInvisible(Player const* player, bool on)
520{
521 auto itr = _playersStore.find(player->GetGUID());
522 if (itr == _playersStore.end())
523 return;
524
525 itr->second.SetInvisible(on);
526
527 // we happen to be owner too, update flag
528 if (_ownerGuid == player->GetGUID())
530}
531
532void Channel::SetModerator(ObjectGuid const& guid, bool set)
533{
534 if (!IsOn(guid))
535 return;
536
537 PlayerInfo& playerInfo = _playersStore.at(guid);
538 if (playerInfo.IsModerator() != set)
539 {
540 uint8 oldFlag = playerInfo.GetFlags();
541 playerInfo.SetModerator(set);
542
543 ModeChangeAppend appender(guid, oldFlag, playerInfo.GetFlags());
544 ChannelNameBuilder<ModeChangeAppend> builder(this, appender);
545 SendToAll(builder);
546 }
547}
548
549void Channel::SetMute(ObjectGuid const& guid, bool set)
550{
551 if (!IsOn(guid))
552 return;
553
554 PlayerInfo& playerInfo = _playersStore.at(guid);
555 if (playerInfo.IsMuted() != set)
556 {
557 uint8 oldFlag = playerInfo.GetFlags();
558 playerInfo.SetMuted(set);
559
560 ModeChangeAppend appender(guid, oldFlag, playerInfo.GetFlags());
561 ChannelNameBuilder<ModeChangeAppend> builder(this, appender);
562 SendToAll(builder);
563 }
564}
565
566void Channel::SetOwner(Player const* player, std::string const& newname)
567{
568 ObjectGuid const& guid = player->GetGUID();
569
570 if (!IsOn(guid))
571 {
572 NotMemberAppend appender;
573 ChannelNameBuilder<NotMemberAppend> builder(this, appender);
574 SendToOne(builder, guid);
575 return;
576 }
577
579 {
580 NotOwnerAppend appender;
581 ChannelNameBuilder<NotOwnerAppend> builder(this, appender);
582 SendToOne(builder, guid);
583 return;
584 }
585
587 ObjectGuid victim = newp ? newp->GetGUID() : ObjectGuid::Empty;
588
589 if (!newp || !victim || !IsOn(victim) ||
590 (player->GetTeam() != newp->GetTeam() &&
593 {
594 PlayerNotFoundAppend appender(newname);
595 ChannelNameBuilder<PlayerNotFoundAppend> builder(this, appender);
596 SendToOne(builder, guid);
597 return;
598 }
599
600 PlayerInfo& info = _playersStore.at(victim);
601 info.SetModerator(true);
602 SetOwner(victim);
603}
604
605void Channel::SendWhoOwner(Player const* player)
606{
607 ObjectGuid const& guid = player->GetGUID();
608 if (IsOn(guid))
609 {
610 ChannelOwnerAppend appender(this, _ownerGuid);
611 ChannelNameBuilder<ChannelOwnerAppend> builder(this, appender);
612 SendToOne(builder, guid);
613 }
614 else
615 {
616 NotMemberAppend appender;
617 ChannelNameBuilder<NotMemberAppend> builder(this, appender);
618 SendToOne(builder, guid);
619 }
620}
621
622void Channel::List(Player const* player) const
623{
624 ObjectGuid const& guid = player->GetGUID();
625 if (!IsOn(guid))
626 {
627 NotMemberAppend appender;
628 ChannelNameBuilder<NotMemberAppend> builder(this, appender);
629 SendToOne(builder, guid);
630 return;
631 }
632
633 std::string channelName = GetName(player->GetSession()->GetSessionDbcLocale());
634 TC_LOG_DEBUG("chat.system", "SMSG_CHANNEL_LIST {} Channel: {}",
635 player->GetSession()->GetPlayerInfo(), channelName);
636
638 list.Display = true;
639 list._Channel = channelName;
640 list._ChannelFlags = GetFlags();
641
642 uint32 gmLevelInWhoList = sWorld->getIntConfig(CONFIG_GM_LEVEL_IN_WHO_LIST);
643
644 list.Members.reserve(_playersStore.size());
645 for (PlayerContainer::value_type const& i : _playersStore)
646 {
648
649 // PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters
650 // MODERATOR, GAME MASTER, ADMINISTRATOR can see all
651 if (member &&
653 member->GetSession()->GetSecurity() <= AccountTypes(gmLevelInWhoList)) &&
654 member->IsVisibleGloballyFor(player))
655 {
656 list.Members.emplace_back(i.first, *member->m_playerData->VirtualPlayerRealm, i.second.GetFlags());
657 }
658 }
659
660 player->SendDirectMessage(list.Write());
661}
662
663void Channel::Announce(Player const* player)
664{
665 ObjectGuid const& guid = player->GetGUID();
666
667 if (!IsOn(guid))
668 {
669 NotMemberAppend appender;
670 ChannelNameBuilder<NotMemberAppend> builder(this, appender);
671 SendToOne(builder, guid);
672 return;
673 }
674
675 PlayerInfo const& playerInfo = _playersStore.at(guid);
677 {
678 NotModeratorAppend appender;
679 ChannelNameBuilder<NotModeratorAppend> builder(this, appender);
680 SendToOne(builder, guid);
681 return;
682 }
683
685
687 {
688 AnnouncementsOnAppend appender(guid);
689 ChannelNameBuilder<AnnouncementsOnAppend> builder(this, appender);
690 SendToAll(builder);
691 }
692 else
693 {
694 AnnouncementsOffAppend appender(guid);
695 ChannelNameBuilder<AnnouncementsOffAppend> builder(this, appender);
696 SendToAll(builder);
697 }
698
699 _isDirty = true;
700}
701
702void Channel::Say(ObjectGuid const& guid, std::string const& what, uint32 lang) const
703{
704 if (what.empty())
705 return;
706
707 // TODO: Add proper RBAC check
709 lang = LANG_UNIVERSAL;
710
711 if (!IsOn(guid))
712 {
713 NotMemberAppend appender;
714 ChannelNameBuilder<NotMemberAppend> builder(this, appender);
715 SendToOne(builder, guid);
716 return;
717 }
718
719 PlayerInfo const& playerInfo = _playersStore.at(guid);
720 if (playerInfo.IsMuted())
721 {
722 MutedAppend appender;
723 ChannelNameBuilder<MutedAppend> builder(this, appender);
724 SendToOne(builder, guid);
725 return;
726 }
727
729
730 auto builder = [&](LocaleConstant locale)
731 {
732 LocaleConstant localeIdx = sWorld->GetAvailableDbcLocale(locale);
733
735 packet->Data.ChannelGUID = _channelGuid;
736 if (player)
737 packet->Data.Initialize(CHAT_MSG_CHANNEL, Language(lang), player, player, what, 0, GetName(localeIdx));
738 else
739 {
740 packet->Data.Initialize(CHAT_MSG_CHANNEL, Language(lang), nullptr, nullptr, what, 0, GetName(localeIdx));
741 packet->Data.SenderGUID = guid;
742 packet->Data.TargetGUID = guid;
743 }
744
745 packet->Data.Write();
746
747 return packet;
748 };
749
750 SendToAll(builder, !playerInfo.IsModerator() ? guid : ObjectGuid::Empty,
751 !playerInfo.IsModerator() && player ? player->GetSession()->GetAccountGUID() : ObjectGuid::Empty);
752}
753
754void Channel::AddonSay(ObjectGuid const& guid, std::string const& prefix, std::string const& what, bool isLogged) const
755{
756 if (what.empty())
757 return;
758
759 if (!IsOn(guid))
760 {
761 NotMemberAppend appender;
762 ChannelNameBuilder<NotMemberAppend> builder(this, appender);
763 SendToOne(builder, guid);
764 return;
765 }
766
767 PlayerInfo const& playerInfo = _playersStore.at(guid);
768 if (playerInfo.IsMuted())
769 {
770 MutedAppend appender;
771 ChannelNameBuilder<MutedAppend> builder(this, appender);
772 SendToOne(builder, guid);
773 return;
774 }
775
777
778 auto builder = [&](LocaleConstant locale)
779 {
780 LocaleConstant localeIdx = sWorld->GetAvailableDbcLocale(locale);
781
783 packet->Data.ChannelGUID = _channelGuid;
784 if (player)
785 packet->Data.Initialize(CHAT_MSG_CHANNEL, isLogged ? LANG_ADDON_LOGGED : LANG_ADDON, player, player, what, 0, GetName(localeIdx), DEFAULT_LOCALE, prefix);
786 else
787 {
788 packet->Data.Initialize(CHAT_MSG_CHANNEL, isLogged ? LANG_ADDON_LOGGED : LANG_ADDON, nullptr, nullptr, what, 0, GetName(localeIdx), DEFAULT_LOCALE, prefix);
789 packet->Data.SenderGUID = guid;
790 packet->Data.TargetGUID = guid;
791 }
792
793 packet->Data.Write();
794
795 return packet;
796 };
797
798 SendToAllWithAddon(builder, prefix, !playerInfo.IsModerator() ? guid : ObjectGuid::Empty,
799 !playerInfo.IsModerator() && player ? player->GetSession()->GetAccountGUID() : ObjectGuid::Empty);
800}
801
802void Channel::Invite(Player const* player, std::string const& newname)
803{
804 ObjectGuid const& guid = player->GetGUID();
805
806 if (!IsOn(guid))
807 {
808 NotMemberAppend appender;
809 ChannelNameBuilder<NotMemberAppend> builder(this, appender);
810 SendToOne(builder, guid);
811 return;
812 }
813
815 if (!newp || !newp->isGMVisible())
816 {
817 PlayerNotFoundAppend appender(newname);
818 ChannelNameBuilder<PlayerNotFoundAppend> builder(this, appender);
819 SendToOne(builder, guid);
820 return;
821 }
822
823 if (IsBanned(newp->GetGUID()))
824 {
825 PlayerInviteBannedAppend appender(newname);
826 ChannelNameBuilder<PlayerInviteBannedAppend> builder(this, appender);
827 SendToOne(builder, guid);
828 return;
829 }
830
831 if (newp->GetTeam() != player->GetTeam() &&
834 {
836 ChannelNameBuilder<InviteWrongFactionAppend> builder(this, appender);
837 SendToOne(builder, guid);
838 return;
839 }
840
841 if (IsOn(newp->GetGUID()))
842 {
843 PlayerAlreadyMemberAppend appender(newp->GetGUID());
844 ChannelNameBuilder<PlayerAlreadyMemberAppend> builder(this, appender);
845 SendToOne(builder, guid);
846 return;
847 }
848
849 if (!newp->GetSocial()->HasIgnore(guid, player->GetSession()->GetAccountGUID()))
850 {
851 InviteAppend appender(guid);
852 ChannelNameBuilder<InviteAppend> builder(this, appender);
853 SendToOne(builder, newp->GetGUID());
854 }
855
856 PlayerInvitedAppend appender(newp->GetName());
857 ChannelNameBuilder<PlayerInvitedAppend> builder(this, appender);
858 SendToOne(builder, guid);
859}
860
861void Channel::SetOwner(ObjectGuid const& guid, bool exclaim)
862{
863 if (!_ownerGuid.IsEmpty())
864 {
865 auto itr = _playersStore.find(_ownerGuid);
866 if (itr != _playersStore.end())
867 itr->second.SetOwner(false);
868 }
869
870 _ownerGuid = guid;
871 if (!_ownerGuid.IsEmpty())
872 {
873 auto itr = _playersStore.find(_ownerGuid);
874 if (itr == _playersStore.end())
875 return;
876
877 uint8 oldFlag = itr->second.GetFlags();
878 itr->second.SetModerator(true);
879 itr->second.SetOwner(true);
880
881 ModeChangeAppend appender(_ownerGuid, oldFlag, itr->second.GetFlags());
882 ChannelNameBuilder<ModeChangeAppend> builder(this, appender);
883 SendToAll(builder);
884
885 if (exclaim)
886 {
887 OwnerChangedAppend ownerAppender(_ownerGuid);
888 ChannelNameBuilder<OwnerChangedAppend> ownerBuilder(this, ownerAppender);
889 SendToAll(ownerBuilder);
890 }
891
892 _isDirty = true;
893 }
894}
895
896void Channel::SilenceAll(Player const* /*player*/, std::string const& /*name*/)
897{
898}
899
900void Channel::UnsilenceAll(Player const* /*player*/, std::string const& /*name*/)
901{
902}
903
904void Channel::DeclineInvite(Player const* /*player*/)
905{
906}
907
908void Channel::JoinNotify(ObjectGuid const& guid) const
909{
910 if (IsConstant())
911 {
912 auto builder = [&](LocaleConstant locale)
913 {
914 LocaleConstant localeIdx = sWorld->GetAvailableDbcLocale(locale);
915
917 userlistAdd->Data.AddedUserGUID = guid;
918 userlistAdd->Data._ChannelFlags = GetFlags();
919 userlistAdd->Data.UserFlags = GetPlayerFlags(guid);
920 userlistAdd->Data.ChannelID = GetChannelId();
921 userlistAdd->Data.ChannelName = GetName(localeIdx);
922 userlistAdd->Data.Write();
923 return userlistAdd;
924 };
925
926 SendToAllButOne(builder, guid);
927 }
928 else
929 {
930 auto builder = [&](LocaleConstant locale)
931 {
932 LocaleConstant localeIdx = sWorld->GetAvailableDbcLocale(locale);
933
935 userlistUpdate->Data.UpdatedUserGUID = guid;
936 userlistUpdate->Data._ChannelFlags = GetFlags();
937 userlistUpdate->Data.UserFlags = GetPlayerFlags(guid);
938 userlistUpdate->Data.ChannelID = GetChannelId();
939 userlistUpdate->Data.ChannelName = GetName(localeIdx);
940 userlistUpdate->Data.Write();
941 return userlistUpdate;
942 };
943
944 SendToAll(builder);
945 }
946}
947
948void Channel::LeaveNotify(ObjectGuid const& guid) const
949{
950 auto builder = [&](LocaleConstant locale)
951 {
952 LocaleConstant localeIdx = sWorld->GetAvailableDbcLocale(locale);
953
955 userlistRemove->Data.RemovedUserGUID = guid;
956 userlistRemove->Data._ChannelFlags = GetFlags();
957 userlistRemove->Data.ChannelID = GetChannelId();
958 userlistRemove->Data.ChannelName = GetName(localeIdx);
959 userlistRemove->Data.Write();
960 return userlistRemove;
961 };
962
963 if (IsConstant())
964 SendToAllButOne(builder, guid);
965 else
966 SendToAll(builder);
967}
968
969template <class Builder>
970void Channel::SendToAll(Builder& builder, ObjectGuid const& guid, ObjectGuid const& accountGuid) const
971{
972 Trinity::LocalizedDo<Builder> localizer(builder);
973
974 for (PlayerContainer::value_type const& i : _playersStore)
975 if (Player* player = ObjectAccessor::FindConnectedPlayer(i.first))
976 if (guid.IsEmpty() || !player->GetSocial()->HasIgnore(guid, accountGuid))
977 localizer(player);
978}
979
980template <class Builder>
981void Channel::SendToAllButOne(Builder& builder, ObjectGuid const& who) const
982{
983 Trinity::LocalizedDo<Builder> localizer(builder);
984
985 for (PlayerContainer::value_type const& i : _playersStore)
986 if (i.first != who)
987 if (Player* player = ObjectAccessor::FindConnectedPlayer(i.first))
988 localizer(player);
989}
990
991template <class Builder>
992void Channel::SendToOne(Builder& builder, ObjectGuid const& who) const
993{
994 Trinity::LocalizedDo<Builder> localizer(builder);
995
997 localizer(player);
998}
999
1000template <class Builder>
1001void Channel::SendToAllWithAddon(Builder& builder, std::string const& addonPrefix, ObjectGuid const& guid /*= ObjectGuid::Empty*/,
1002 ObjectGuid const& accountGuid /*= ObjectGuid::Empty*/) const
1003{
1004 Trinity::LocalizedDo<Builder> localizer(builder);
1005
1006 for (PlayerContainer::value_type const& i : _playersStore)
1007 if (Player* player = ObjectAccessor::FindConnectedPlayer(i.first))
1008 if (player->GetSession()->IsAddonRegistered(addonPrefix) && (guid.IsEmpty() || !player->GetSocial()->HasIgnore(guid, accountGuid)))
1009 localizer(player);
1010}
@ CHANNEL_FLAG_TRADE
Definition Channel.h:81
@ CHANNEL_FLAG_NOT_LFG
Definition Channel.h:82
@ CHANNEL_FLAG_GENERAL
Definition Channel.h:83
@ CHANNEL_FLAG_CUSTOM
Definition Channel.h:79
@ CHANNEL_FLAG_LFG
Definition Channel.h:85
@ CHANNEL_FLAG_CITY
Definition Channel.h:84
@ 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:74
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition Log.h:173
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:43
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
void List(Player const *player) const
Definition Channel.cpp:622
bool IsConstant() const
Definition Channel.h:167
void Password(Player const *player, std::string const &pass)
Definition Channel.cpp:437
uint32 _channelId
Definition Channel.h:259
BannedContainer _bannedStore
Definition Channel.h:266
void LeaveNotify(ObjectGuid const &guid) const
Definition Channel.cpp:948
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:1001
bool _ownershipEnabled
Definition Channel.h:255
bool _announceEnabled
Definition Channel.h:254
void SendToOne(Builder &builder, ObjectGuid const &who) const
Definition Channel.cpp:992
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:981
Channel(ObjectGuid const &guid, uint32 channelId, uint32 team=0, AreaTableEntry const *zoneEntry=nullptr)
Definition Channel.cpp:38
void JoinNotify(ObjectGuid const &guid) const
Definition Channel.cpp:908
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:326
bool _isOwnerInvisible
Definition Channel.h:256
uint32 GetChannelId() const
Definition Channel.h:166
void SendWhoOwner(Player const *player)
Definition Channel.cpp:605
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:900
void AddonSay(ObjectGuid const &guid, std::string const &prefix, std::string const &what, bool isLogged) const
Definition Channel.cpp:754
void SetOwner(ObjectGuid const &guid, bool exclaim=true)
Definition Channel.cpp:861
void UnBan(Player const *player, std::string const &badname)
Definition Channel.cpp:396
void SilenceAll(Player const *player, std::string const &name)
Definition Channel.cpp:896
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:467
void Say(ObjectGuid const &guid, std::string const &what, uint32 lang) const
Definition Channel.cpp:702
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:904
void SetInvisible(Player const *player, bool on)
Definition Channel.cpp:519
void UpdateChannelInDB()
Definition Channel.cpp:124
void Announce(Player const *player)
Definition Channel.cpp:663
void Invite(Player const *player, std::string const &newp)
Definition Channel.cpp:802
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:970
AreaTableEntry const * _zoneEntry
Definition Channel.h:268
ObjectGuid _ownerGuid
Definition Channel.h:262
std::string _channelPassword
Definition Channel.h:264
void LeaveChannel(Player *player, bool send=true, bool suspend=false)
Definition Channel.cpp:253
uint8 GetFlags() const
Definition Channel.h:185
PlayerContainer _playersStore
Definition Channel.h:265
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:3047
bool isGMVisible() const
Definition Player.h:1301
PlayerSocial * GetSocial() const
Definition Player.h:1274
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6193
WorldSession * GetSession() const
Definition Player.h:2256
bool IsVisibleGloballyFor(Player const *player) const
Definition Player.cpp:24478
Group * GetGroup(Optional< uint8 > partyIndex)
Definition Player.h:2781
void LeftChannel(Channel *c)
Definition Player.cpp:4758
void JoinedChannel(Channel *c)
Definition Player.cpp:4753
Team GetTeam() const
Definition Player.h:2406
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:919
@ CONFIG_PRESERVE_CUSTOM_CHANNEL_INTERVAL
Definition World.h:376
@ 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:130
bool IsOwner() const
Definition Channel.h:120
uint8 GetFlags() const
Definition Channel.h:111
bool IsMuted() const
Definition Channel.h:138
bool IsInvisible() const
Definition Channel.h:113
void SetInvisible(bool on)
Definition Channel.h:114
void SetMuted(bool state)
Definition Channel.h:139
bool IsModerator() const
Definition Channel.h:129
LocalizedString Name
EnumFlag< ChatChannelFlags > GetFlags() const