Files
Hondacrx d70529bc19 Core/Realms: Realmlist refactors
* Removed global realm variable from World and use RealmList everywhere
* Match auth build key with client version
* Restored allowedSecurityLevel checks for realmlist packet building
* Restored updating population field
Port From (https://github.com/TrinityCore/TrinityCore/commit/c4b710446d62c95eb8124175203fa5f394912594)
2024-09-26 12:53:15 -04:00

249 lines
9.3 KiB
C#

// Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved.
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
using Framework.Constants;
using Framework.Database;
using Game.DataStorage;
using Game.Entities;
using Game.Networking.Packets;
using System;
using System.Collections.Generic;
namespace Game.Chat
{
public class ChannelManager
{
public static AreaTableRecord SpecialLinkedArea { get; private set; }
public ChannelManager(Team team)
{
_team = team;
_guidGenerator = new ObjectGuidGenerator(HighGuid.ChatChannel);
}
public static void LoadFromDB()
{
SpecialLinkedArea = CliDB.AreaTableStorage.LookupByKey(3459);
Cypher.Assert(SpecialLinkedArea.HasFlag(AreaFlags.LinkedChatSpecialArea));
if (!WorldConfig.GetBoolValue(WorldCfg.PreserveCustomChannels))
{
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 custom chat channels. Custom channel saving is disabled.");
return;
}
uint oldMSTime = Time.GetMSTime();
uint days = WorldConfig.GetUIntValue(WorldCfg.PreserveCustomChannelDuration);
if (days != 0)
{
PreparedStatement stmt = CharacterDatabase.GetPreparedStatement(CharStatements.DEL_OLD_CHANNELS);
stmt.AddValue(0, days * Time.Day);
DB.Characters.Execute(stmt);
}
SQLResult result = DB.Characters.Query("SELECT name, team, announce, ownership, password, bannedList FROM channels");
if (result.IsEmpty())
{
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 custom chat channels. DB table `channels` is empty.");
return;
}
List<(string name, Team team)> toDelete = new();
uint count = 0;
do
{
string dbName = result.Read<string>(0); // may be different - channel names are case insensitive
Team team = (Team)result.Read<int>(1);
bool dbAnnounce = result.Read<bool>(2);
bool dbOwnership = result.Read<bool>(3);
string dbPass = result.Read<string>(4);
string dbBanned = result.Read<string>(5);
ChannelManager mgr = ForTeam(team);
if (mgr == null)
{
Log.outError(LogFilter.ServerLoading, $"Failed to load custom chat channel '{dbName}' from database - invalid team {team}. Deleted.");
toDelete.Add((dbName, team));
continue;
}
Channel channel = new Channel(mgr.CreateCustomChannelGuid(), dbName, team, dbBanned);
channel.SetAnnounce(dbAnnounce);
channel.SetOwnership(dbOwnership);
channel.SetPassword(dbPass);
mgr._customChannels.Add(dbName, channel);
++count;
} while (result.NextRow());
foreach (var (name, team) in toDelete)
{
PreparedStatement stmt = CharacterDatabase.GetPreparedStatement(CharStatements.DEL_CHANNEL);
stmt.AddValue(0, name);
stmt.AddValue(1, (uint)team);
DB.Characters.Execute(stmt);
}
Log.outInfo(LogFilter.ServerLoading, $"Loaded {count} custom chat channels in {Time.GetMSTimeDiffToNow(oldMSTime)} ms");
}
public static ChannelManager ForTeam(Team team)
{
if (WorldConfig.GetBoolValue(WorldCfg.AllowTwoSideInteractionChannel))
return neutralChannelMgr; // cross-faction
return team switch
{
Team.Alliance => allianceChannelMgr,
Team.Horde => hordeChannelMgr,
Team.PandariaNeutral => neutralChannelMgr,
_ => null
};
}
public static Channel GetChannelForPlayerByNamePart(string namePart, Player playerSearcher)
{
foreach (Channel channel in playerSearcher.GetJoinedChannels())
{
string chanName = channel.GetName(playerSearcher.GetSession().GetSessionDbcLocale());
if (chanName.ToLower().Equals(namePart.ToLower()))
return channel;
}
return null;
}
public void SaveToDB()
{
foreach (var pair in _customChannels)
pair.Value.UpdateChannelInDB();
}
public static Channel GetChannelForPlayerByGuid(ObjectGuid channelGuid, Player playerSearcher)
{
foreach (Channel channel in playerSearcher.GetJoinedChannels())
if (channel.GetGUID() == channelGuid)
return channel;
return null;
}
public Channel GetSystemChannel(uint channelId, AreaTableRecord zoneEntry = null)
{
ObjectGuid channelGuid = CreateBuiltinChannelGuid(channelId, zoneEntry);
var currentChannel = _channels.LookupByKey(channelGuid);
if (currentChannel != null)
return currentChannel;
Channel newChannel = new Channel(channelGuid, channelId, _team, zoneEntry);
_channels[channelGuid] = newChannel;
return newChannel;
}
public Channel CreateCustomChannel(string name)
{
if (_customChannels.ContainsKey(name.ToLower()))
return null;
Channel newChannel = new(CreateCustomChannelGuid(), name, _team);
newChannel.SetDirty();
_customChannels[name.ToLower()] = newChannel;
return newChannel;
}
public Channel GetCustomChannel(string name)
{
return _customChannels.LookupByKey(name.ToLower());
}
public Channel GetChannel(uint channelId, string name, Player player, bool notify = true, AreaTableRecord zoneEntry = null)
{
Channel result = null;
if (channelId != 0) // builtin
{
var channel = _channels.LookupByKey(CreateBuiltinChannelGuid(channelId, zoneEntry));
if (channel != null)
result = channel;
}
else // custom
{
var channel = _customChannels.LookupByKey(name.ToLower());
if (channel != null)
result = channel;
}
if (result == null && notify)
{
string channelName = name;
Channel.GetChannelName(ref channelName, channelId, player.GetSession().GetSessionDbcLocale(), zoneEntry);
SendNotOnChannelNotify(player, channelName);
}
return result;
}
public void LeftChannel(uint channelId, AreaTableRecord zoneEntry)
{
var guid = CreateBuiltinChannelGuid(channelId, zoneEntry);
var channel = _channels.LookupByKey(guid);
if (channel == null)
return;
if (channel.GetNumPlayers() == 0)
_channels.Remove(guid);
}
public static void SendNotOnChannelNotify(Player player, string name)
{
ChannelNotify notify = new();
notify.Type = ChatNotify.NotMemberNotice;
notify.Channel = name;
player.SendPacket(notify);
}
ObjectGuid CreateCustomChannelGuid()
{
ulong high = 0;
high |= (ulong)HighGuid.ChatChannel << 58;
high |= (ulong)Global.RealmMgr.GetCurrentRealmId().Index << 42;
high |= (ulong)(_team == Team.Alliance ? 3 : 5) << 4;
ObjectGuid channelGuid = new();
channelGuid.SetRawValue(high, _guidGenerator.Generate());
return channelGuid;
}
ObjectGuid CreateBuiltinChannelGuid(uint channelId, AreaTableRecord zoneEntry = null)
{
ChatChannelsRecord channelEntry = CliDB.ChatChannelsStorage.LookupByKey(channelId);
uint zoneId = 0;
if (zoneEntry != null && channelEntry.HasFlag(ChatChannelFlags.ZoneBased) && !channelEntry.HasFlag(ChatChannelFlags.LinkedChannel))
zoneId = zoneEntry.Id;
if (channelEntry.HasFlag(ChatChannelFlags.GlobalForTournament))
{
var currentRealm = Global.RealmMgr.GetCurrentRealm();
if (currentRealm != null)
{
var category = CliDB.CfgCategoriesStorage.LookupByKey(currentRealm.Timezone);
if (category != null && category.HasFlag(CfgCategoriesFlags.Tournament))
zoneId = 0;
}
}
return ObjectGuid.Create(HighGuid.ChatChannel, true, channelEntry.HasFlag(ChatChannelFlags.LinkedChannel), (ushort)zoneId, (byte)(_team == Team.Alliance ? 3 : 5), channelId);
}
Dictionary<string, Channel> _customChannels = new();
Dictionary<ObjectGuid, Channel> _channels = new();
Team _team;
ObjectGuidGenerator _guidGenerator;
static ChannelManager allianceChannelMgr = new(Team.Alliance);
static ChannelManager hordeChannelMgr = new(Team.Horde);
static ChannelManager neutralChannelMgr = new(Team.PandariaNeutral);
}
}