diff --git a/Source/BNetServer/Networking/Services/GameUtilities.cs b/Source/BNetServer/Networking/Services/GameUtilities.cs index ca6efd24b..7244de0a0 100644 --- a/Source/BNetServer/Networking/Services/GameUtilities.cs +++ b/Source/BNetServer/Networking/Services/GameUtilities.cs @@ -146,7 +146,7 @@ namespace BNetServer.Networking var lastPlayerChar = gameAccountInfo.LastPlayedCharacters.LookupByKey(subRegion.StringValue); if (lastPlayerChar != null) { - var compressed = Global.RealmMgr.GetRealmEntryJSON(lastPlayerChar.RealmId, build); + var compressed = Global.RealmMgr.GetRealmEntryJSON(lastPlayerChar.RealmId, build, gameAccountInfo.SecurityLevel); if (compressed.Length == 0) return BattlenetRpcErrorCode.UtilServerFailedToSerializeResponse; @@ -191,7 +191,7 @@ namespace BNetServer.Networking if (subRegion != null) subRegionId = subRegion.StringValue; - var compressed = Global.RealmMgr.GetRealmList(build, subRegionId); + var compressed = Global.RealmMgr.GetRealmList(build, gameAccountInfo.SecurityLevel, subRegionId); if (compressed.Length == 0) return BattlenetRpcErrorCode.UtilServerFailedToSerializeResponse; @@ -227,7 +227,7 @@ namespace BNetServer.Networking { Variant realmAddress = Params.LookupByKey("Param_RealmAddress"); if (realmAddress != null) - return Global.RealmMgr.JoinRealm((uint)realmAddress.UintValue, build, GetRemoteIpAddress(), clientSecret, (Locale)Enum.Parse(typeof(Locale), locale), os, _timezoneOffset, gameAccountInfo.Name, response); + return Global.RealmMgr.JoinRealm((uint)realmAddress.UintValue, build, GetRemoteIpAddress(), clientSecret, (Locale)Enum.Parse(typeof(Locale), locale), os, _timezoneOffset, gameAccountInfo.Name, gameAccountInfo.SecurityLevel, response); return BattlenetRpcErrorCode.WowServicesInvalidJoinTicket; } diff --git a/Source/Framework/Constants/Authentication/RealmConst.cs b/Source/Framework/Constants/Authentication/RealmConst.cs index b2ea0b6ce..8fbc6056f 100644 --- a/Source/Framework/Constants/Authentication/RealmConst.cs +++ b/Source/Framework/Constants/Authentication/RealmConst.cs @@ -7,6 +7,20 @@ namespace Framework.Constants { [Flags] public enum RealmFlags + { + None = 0x00, + VersionMismatch = 0x01, + Hidden = 0x02, + Tournament = 0x04, + VersionBelow = 0x08, + VersionAbove = 0x10, + MobileVersionMismatch = 0x20, + MobileVersionBelow = 0x40, + MobileVersionAbove = 0x80 + } + + [Flags] + public enum LegacyRealmFlags { None = 0x00, VersionMismatch = 0x01, @@ -19,6 +33,18 @@ namespace Framework.Constants Full = 0x80 } + public enum RealmPopulationState + { + Offline = 0, + Low = 1, + Medium = 2, + High = 3, + New = 4, + Recommended = 5, + Full = 6, + Locked = 7 + } + public enum RealmType { Normal = 0, diff --git a/Source/Framework/Database/Databases/LoginDatabase.cs b/Source/Framework/Database/Databases/LoginDatabase.cs index 60d3f7cd4..31712854e 100644 --- a/Source/Framework/Database/Databases/LoginDatabase.cs +++ b/Source/Framework/Database/Databases/LoginDatabase.cs @@ -11,6 +11,7 @@ namespace Framework.Database const string BnetGameAccountInfo = "a.id, a.username, ab.unbandate, ab.unbandate = ab.bandate, aa.SecurityLevel"; PrepareStatement(LoginStatements.SEL_REALMLIST, "SELECT id, name, address, localAddress, port, icon, flag, timezone, allowedSecurityLevel, population, gamebuild, Region, Battlegroup FROM realmlist WHERE flag <> 3 ORDER BY name"); + PrepareStatement(LoginStatements.UPD_REALM_POPULATION, "UPDATE realmlist SET population = ? WHERE id = ?"); PrepareStatement(LoginStatements.DEL_EXPIRED_IP_BANS, "DELETE FROM ip_banned WHERE unbandate<>bandate AND unbandate<=UNIX_TIMESTAMP()"); PrepareStatement(LoginStatements.UPD_EXPIRED_ACCOUNT_BANS, "UPDATE account_banned SET active = 0 WHERE active = 1 AND unbandate<>bandate AND unbandate<=UNIX_TIMESTAMP()"); PrepareStatement(LoginStatements.SEL_IP_INFO, "SELECT unbandate > UNIX_TIMESTAMP() OR unbandate = bandate AS banned, NULL as country FROM ip_banned WHERE ip = ?"); @@ -26,7 +27,7 @@ namespace Framework.Database PrepareStatement(LoginStatements.UPD_LOGON, "UPDATE account SET salt = ?, verifier = ? WHERE id = ?"); PrepareStatement(LoginStatements.SEL_ACCOUNT_ID_BY_NAME, "SELECT id FROM account WHERE username = ?"); PrepareStatement(LoginStatements.SEL_ACCOUNT_LIST_BY_NAME, "SELECT id, username FROM account WHERE username = ?"); - PrepareStatement(LoginStatements.SEL_ACCOUNT_INFO_BY_NAME, "SELECT a.id, a.session_key_bnet, ba.last_ip, ba.locked, ba.lock_country, a.expansion, a.mutetime, ba.locale, a.recruiter, a.os, a.timezone_offset, ba.id, aa.SecurityLevel, " + + PrepareStatement(LoginStatements.SEL_ACCOUNT_INFO_BY_NAME, "SELECT a.id, a.session_key_bnet, ba.last_ip, ba.locked, ba.lock_country, a.expansion, a.mutetime, a.client_build, a.locale, a.recruiter, a.os, a.timezone_offset, ba.id, aa.SecurityLevel, " + "bab.unbandate > UNIX_TIMESTAMP() OR bab.unbandate = bab.bandate, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, r.id " + "FROM account a LEFT JOIN account r ON a.id = r.recruiter LEFT JOIN battlenet_accounts ba ON a.battlenet_account = ba.id " + "LEFT JOIN account_access aa ON a.id = aa.AccountID AND aa.RealmID IN (-1, ?) LEFT JOIN battlenet_account_bans bab ON ba.id = bab.id LEFT JOIN account_banned ab ON a.id = ab.id AND ab.active = 1 " + @@ -74,7 +75,6 @@ namespace Framework.Database PrepareStatement(LoginStatements.SEL_ACCOUNT_WHOIS, "SELECT username, email, last_ip FROM account WHERE id = ?"); PrepareStatement(LoginStatements.SEL_LAST_ATTEMPT_IP, "SELECT last_attempt_ip FROM account WHERE id = ?"); PrepareStatement(LoginStatements.SEL_LAST_IP, "SELECT last_ip FROM account WHERE id = ?"); - PrepareStatement(LoginStatements.SEL_REALMLIST_SECURITY_LEVEL, "SELECT allowedSecurityLevel from realmlist WHERE id = ?"); PrepareStatement(LoginStatements.DEL_ACCOUNT, "DELETE FROM account WHERE id = ?"); PrepareStatement(LoginStatements.SEL_AUTOBROADCAST, "SELECT id, weight, text FROM autobroadcast WHERE realmid = ? OR realmid = -1"); PrepareStatement(LoginStatements.GET_EMAIL_BY_ID, "SELECT email FROM account WHERE id = ?"); @@ -112,7 +112,7 @@ namespace Framework.Database " FROM battlenet_accounts ba LEFT JOIN battlenet_account_bans bab ON ba.id = bab.id LEFT JOIN account a ON ba.id = a.battlenet_account" + " LEFT JOIN account_banned ab ON a.id = ab.id AND ab.active = 1 LEFT JOIN account_access aa ON a.id = aa.AccountID AND aa.RealmID = -1 WHERE ba.LoginTicket = ? ORDER BY a.id"); PrepareStatement(LoginStatements.UPD_BNET_LAST_LOGIN_INFO, "UPDATE battlenet_accounts SET last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ? WHERE id = ?"); - PrepareStatement(LoginStatements.UPD_BNET_GAME_ACCOUNT_LOGIN_INFO, "UPDATE account SET session_key_bnet = ?, last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ?, timezone_offset = ? WHERE username = ?"); + PrepareStatement(LoginStatements.UPD_BNET_GAME_ACCOUNT_LOGIN_INFO, "UPDATE account SET session_key_bnet = ?, last_ip = ?, last_login = NOW(), client_build = ?, locale = ?, failed_logins = 0, os = ?, timezone_offset = ? WHERE username = ?"); PrepareStatement(LoginStatements.SEL_BNET_CHARACTER_COUNTS_BY_ACCOUNT_ID, "SELECT rc.acctid, rc.numchars, r.id, r.Region, r.Battlegroup FROM realmcharacters rc INNER JOIN realmlist r ON rc.realmid = r.id WHERE rc.acctid = ?"); PrepareStatement(LoginStatements.SEL_BNET_CHARACTER_COUNTS_BY_BNET_ID, "SELECT rc.acctid, rc.numchars, r.id, r.Region, r.Battlegroup FROM realmcharacters rc INNER JOIN realmlist r ON rc.realmid = r.id LEFT JOIN account a ON rc.acctid = a.id WHERE a.battlenet_account = ?"); PrepareStatement(LoginStatements.SEL_BNET_LAST_PLAYER_CHARACTERS, "SELECT lpc.accountId, lpc.region, lpc.battlegroup, lpc.realmId, lpc.characterName, lpc.characterGUID, lpc.lastPlayedTime FROM account_last_played_character lpc LEFT JOIN account a ON lpc.accountId = a.id WHERE a.battlenet_account = ?"); @@ -145,7 +145,7 @@ namespace Framework.Database PrepareStatement(LoginStatements.REP_ACCOUNT_TOYS, "REPLACE INTO battlenet_account_toys (accountId, itemId, isFavourite, hasFanfare) VALUES (?, ?, ?, ?)"); // Battle Pets - PrepareStatement(LoginStatements.SEL_BATTLE_PETS, "SELECT bp.guid, bp.species, bp.breed, bp.displayId, bp.level, bp.exp, bp.health, bp.quality, bp.flags, bp.name, bp.nameTimestamp, bp.owner, dn.genitive, dn.dative, dn.accusative, dn.instrumental, dn.prepositional FROM battle_pets bp LEFT JOIN battle_pet_declinedname dn ON bp.guid = dn.guid WHERE bp.battlenetAccountId = ? AND (bp.ownerRealmId IS NULL OR bp.ownerRealmId = ?)"); + PrepareStatement(LoginStatements.SEL_BATTLE_PETS, "SELECT bp.guid, bp.species, bp.breed, bp.displayId, bp.level, bp.exp, bp.health, bp.quality, bp.flags, bp.name, bp.nameTimestamp, bp.owner, bp.ownerRealmId, dn.genitive, dn.dative, dn.accusative, dn.instrumental, dn.prepositional FROM battle_pets bp LEFT JOIN battle_pet_declinedname dn ON bp.guid = dn.guid WHERE bp.battlenetAccountId = ? AND (bp.ownerRealmId IS NULL OR bp.ownerRealmId = ?)"); PrepareStatement(LoginStatements.INS_BATTLE_PETS, "INSERT INTO battle_pets (guid, battlenetAccountId, species, breed, displayId, level, exp, health, quality, flags, name, nameTimestamp, owner, ownerRealmId) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); PrepareStatement(LoginStatements.DEL_BATTLE_PETS, "DELETE FROM battle_pets WHERE battlenetAccountId = ? AND guid = ?"); PrepareStatement(LoginStatements.DEL_BATTLE_PETS_BY_OWNER, "DELETE FROM battle_pets WHERE owner = ? AND ownerRealmId = ?"); @@ -180,6 +180,7 @@ namespace Framework.Database public enum LoginStatements { SEL_REALMLIST, + UPD_REALM_POPULATION, DEL_EXPIRED_IP_BANS, UPD_EXPIRED_ACCOUNT_BANS, SEL_IP_INFO, @@ -237,7 +238,6 @@ namespace Framework.Database SEL_ACCOUNT_ACCESS_SECLEVEL_TEST, SEL_ACCOUNT_ACCESS, SEL_ACCOUNT_WHOIS, - SEL_REALMLIST_SECURITY_LEVEL, DEL_ACCOUNT, SEL_AUTOBROADCAST, SEL_LAST_ATTEMPT_IP, diff --git a/Source/Framework/Realm/Realm.cs b/Source/Framework/Realm/Realm.cs index dfa0c6943..418ece87c 100644 --- a/Source/Framework/Realm/Realm.cs +++ b/Source/Framework/Realm/Realm.cs @@ -66,6 +66,6 @@ public class Realm : IEquatable public RealmFlags Flags; public byte Timezone; public AccountTypes AllowedSecurityLevel; - public float PopulationLevel; + public RealmPopulationState PopulationLevel; } diff --git a/Source/Framework/Realm/RealmManager.cs b/Source/Framework/Realm/RealmManager.cs index 2f44721a8..2a497a449 100644 --- a/Source/Framework/Realm/RealmManager.cs +++ b/Source/Framework/Realm/RealmManager.cs @@ -83,6 +83,7 @@ public class RealmManager : Singleton { PreparedStatement stmt = LoginDatabase.GetPreparedStatement(LoginStatements.SEL_REALMLIST); SQLResult result = DB.Login.Query(stmt); + Dictionary existingRealms = new(); foreach (var p in _realms) existingRealms[p.Key] = p.Value.Name; @@ -94,11 +95,26 @@ public class RealmManager : Singleton { do { - var realm = new Realm(); uint realmId = result.Read(0); - realm.Name = result.Read(1); - realm.Addresses.Add(IPAddress.Parse(result.Read(2))); - realm.Addresses.Add(IPAddress.Parse(result.Read(3))); + string name = result.Read(1); + string externalAddressString = result.Read(2); + string localAddressString = result.Read(3); + + if (!IPAddress.TryParse(externalAddressString, out IPAddress externalAddress)) + { + Log.outError(LogFilter.Realmlist, $"Could not resolve address {externalAddressString} for realm \"{name}\" id {realmId}"); + continue; + } + + if (!IPAddress.TryParse(localAddressString, out IPAddress localAddress)) + { + Log.outError(LogFilter.Realmlist, $"Could not resolve localAddress {localAddressString} for realm \"{name}\" id {realmId}"); + continue; + } + + var realm = new Realm(); + realm.Addresses.Add(externalAddress); + realm.Addresses.Add(localAddress); realm.Port = result.Read(4); RealmType realmType = (RealmType)result.Read(5); if (realmType == RealmType.FFAPVP) @@ -107,11 +123,11 @@ public class RealmManager : Singleton realmType = RealmType.Normal; realm.Type = (byte)realmType; - realm.Flags = (RealmFlags)result.Read(6); + realm.Flags = ConvertLegacyRealmFlags((LegacyRealmFlags)result.Read(6)); realm.Timezone = result.Read(7); AccountTypes allowedSecurityLevel = (AccountTypes)result.Read(8); realm.AllowedSecurityLevel = (allowedSecurityLevel <= AccountTypes.Administrator ? allowedSecurityLevel : AccountTypes.Administrator); - realm.PopulationLevel = result.Read(9); + realm.PopulationLevel = ConvertLegacyPopulationState((LegacyRealmFlags)result.Read(6), result.Read(9)); realm.Build = result.Read(10); byte region = result.Read(11); byte battlegroup = result.Read(12); @@ -125,9 +141,9 @@ public class RealmManager : Singleton _subRegions.Add(subRegion); if (!existingRealms.ContainsKey(realm.Id)) - Log.outInfo(LogFilter.Realmlist, "Added realm \"{0}\" at {1}:{2}", realm.Name, realm.Addresses[0].ToString(), realm.Port); + Log.outInfo(LogFilter.Realmlist, $"Added realm \"{realm.Name}\" at {externalAddressString}:{realm.Port}"); else - Log.outDebug(LogFilter.Realmlist, "Updating realm \"{0}\" at {1}:{2}", realm.Name, realm.Addresses[0].ToString(), realm.Port); + Log.outDebug(LogFilter.Realmlist, $"Updating realm \"{realm.Name}\" at {externalAddressString}:{realm.Port}"); existingRealms.Remove(realm.Id); } @@ -136,6 +152,15 @@ public class RealmManager : Singleton foreach (var pair in existingRealms) Log.outInfo(LogFilter.Realmlist, "Removed realm \"{0}\".", pair.Value); + + _removedRealms = existingRealms; + + if (_currentRealmId.HasValue) + { + var realm = _realms.LookupByKey(_currentRealmId.Value); + if (realm != null) + _currentRealmId = realm.Id; // fill other fields of realm id + } } public Realm GetRealm(RealmId id) @@ -143,18 +168,31 @@ public class RealmManager : Singleton return _realms.LookupByKey(id); } - public bool GetRealmNames(RealmId id, out string name, out string normalizedName) + public RealmId GetCurrentRealmId() { - name = null; - normalizedName = null; + return _currentRealmId.HasValue ? _currentRealmId.Value : new(); + } - Realm realm = GetRealm(id); - if (realm == null) - return false; + public void SetCurrentRealmId(RealmId id) + { + _currentRealmId = id; + } - name = realm.Name; - normalizedName = realm.NormalizedName; - return true; + public Realm GetCurrentRealm() + { + if (_currentRealmId.HasValue) + return GetRealm(_currentRealmId.Value); + return null; + } + + public void WriteSubRegions(Bgs.Protocol.GameUtilities.V1.GetAllValuesForAttributeResponse response) + { + foreach (string subRegion in GetSubRegions()) + { + var variant = new Bgs.Protocol.Variant(); + variant.StringValue = subRegion; + response.AttributeValue.Add(variant); + } } public RealmBuildInfo GetBuildInfo(uint build) @@ -172,121 +210,100 @@ public class RealmManager : Singleton return buildInfo != null ? (buildInfo.MajorVersion * 10000 + buildInfo.MinorVersion * 100 + buildInfo.BugfixVersion) : 0; } - public void WriteSubRegions(Bgs.Protocol.GameUtilities.V1.GetAllValuesForAttributeResponse response) + void FillRealmEntry(Realm realm, uint clientBuild, AccountTypes accountSecurityLevel, RealmEntry realmEntry) { - foreach (string subRegion in GetSubRegions()) + realmEntry.WowRealmAddress = (int)realm.Id.GetAddress(); + realmEntry.CfgTimezonesID = 1; + if (accountSecurityLevel >= realm.AllowedSecurityLevel || realm.PopulationLevel == RealmPopulationState.Offline) + realmEntry.PopulationState = (int)realm.PopulationLevel; + else + realmEntry.PopulationState = (int)RealmPopulationState.Locked; + + realmEntry.CfgCategoriesID = realm.Timezone; + + ClientVersion version = new(); + RealmBuildInfo buildInfo = GetBuildInfo(realm.Build); + if (buildInfo != null) { - var variant = new Bgs.Protocol.Variant(); - variant.StringValue = subRegion; - response.AttributeValue.Add(variant); + version.Major = (int)buildInfo.MajorVersion; + version.Minor = (int)buildInfo.MinorVersion; + version.Revision = (int)buildInfo.BugfixVersion; + version.Build = (int)buildInfo.Build; } + else + { + version.Major = 6; + version.Minor = 2; + version.Revision = 4; + version.Build = (int)realm.Build; + } + + RealmFlags flag = realm.Flags; + if (realm.Build != clientBuild) + flag |= RealmFlags.VersionMismatch; + + realmEntry.Version = version; + + realmEntry.CfgRealmsID = (int)realm.Id.Index; + realmEntry.Flags = (int)flag; + realmEntry.Name = realm.Name; + realmEntry.CfgConfigsID = (int)realm.GetConfigId(); + realmEntry.CfgLanguagesID = 1; } - public byte[] GetRealmEntryJSON(RealmId id, uint build) + public byte[] GetRealmEntryJSON(RealmId id, uint build, AccountTypes accountSecurityLevel) { - byte[] compressed = new byte[0]; + byte[] compressed = []; Realm realm = GetRealm(id); if (realm != null) { - if (!realm.Flags.HasAnyFlag(RealmFlags.Offline) && realm.Build == build) + if (realm.PopulationLevel != RealmPopulationState.Offline && realm.Build == build && accountSecurityLevel >= realm.AllowedSecurityLevel) { - var realmEntry = new RealmEntry(); - realmEntry.WowRealmAddress = (int)realm.Id.GetAddress(); - realmEntry.CfgTimezonesID = 1; - realmEntry.PopulationState = Math.Max((int)realm.PopulationLevel, 1); - realmEntry.CfgCategoriesID = realm.Timezone; - - ClientVersion version = new(); - RealmBuildInfo buildInfo = GetBuildInfo(realm.Build); - if (buildInfo != null) - { - version.Major = (int)buildInfo.MajorVersion; - version.Minor = (int)buildInfo.MinorVersion; - version.Revision = (int)buildInfo.BugfixVersion; - version.Build = (int)buildInfo.Build; - } - else - { - version.Major = 6; - version.Minor = 2; - version.Revision = 4; - version.Build = (int)realm.Build; - } - realmEntry.Version = version; - - realmEntry.CfgRealmsID = (int)realm.Id.Index; - realmEntry.Flags = (int)realm.Flags; - realmEntry.Name = realm.Name; - realmEntry.CfgConfigsID = (int)realm.GetConfigId(); - realmEntry.CfgLanguagesID = 1; - + RealmEntry realmEntry = new(); + FillRealmEntry(realm, build, accountSecurityLevel, realmEntry); var jsonData = Encoding.UTF8.GetBytes("JamJSONRealmEntry:" + JsonSerializer.Serialize(realmEntry) + "\0"); - var compressedData = ZLib.Compress(jsonData); - - compressed = BitConverter.GetBytes(jsonData.Length).Combine(compressedData); + compressed = BitConverter.GetBytes(jsonData.Length).Combine(ZLib.Compress(jsonData)); } } return compressed; } - public byte[] GetRealmList(uint build, string subRegion) + public byte[] GetRealmList(uint build, AccountTypes accountSecurityLevel, string subRegion) { var realmList = new RealmListUpdates(); - foreach (var realm in _realms) + foreach (var (_, realm) in _realms) { - if (realm.Value.Id.GetSubRegionAddress() != subRegion) + if (realm.Id.GetSubRegionAddress() != subRegion) continue; - RealmFlags flag = realm.Value.Flags; - if (realm.Value.Build != build) - flag |= RealmFlags.VersionMismatch; + RealmListUpdatePart state = new(); + FillRealmEntry(realm, build, accountSecurityLevel, state.Update); + state.Deleting = false; + realmList.Updates.Add(state); + } - RealmListUpdate realmListUpdate = new(); - realmListUpdate.Update.WowRealmAddress = (int)realm.Value.Id.GetAddress(); - realmListUpdate.Update.CfgTimezonesID = 1; - realmListUpdate.Update.PopulationState = (realm.Value.Flags.HasAnyFlag(RealmFlags.Offline) ? 0 : Math.Max((int)realm.Value.PopulationLevel, 1)); - realmListUpdate.Update.CfgCategoriesID = realm.Value.Timezone; + foreach (var (id, _) in _removedRealms) + { + if (id.GetSubRegionAddress() != subRegion) + continue; - RealmBuildInfo buildInfo = GetBuildInfo(realm.Value.Build); - if (buildInfo != null) - { - realmListUpdate.Update.Version.Major = (int)buildInfo.MajorVersion; - realmListUpdate.Update.Version.Minor = (int)buildInfo.MinorVersion; - realmListUpdate.Update.Version.Revision = (int)buildInfo.BugfixVersion; - realmListUpdate.Update.Version.Build = (int)buildInfo.Build; - } - else - { - realmListUpdate.Update.Version.Major = 7; - realmListUpdate.Update.Version.Minor = 1; - realmListUpdate.Update.Version.Revision = 0; - realmListUpdate.Update.Version.Build = (int)realm.Value.Build; - } - - realmListUpdate.Update.CfgRealmsID = (int)realm.Value.Id.Index; - realmListUpdate.Update.Flags = (int)flag; - realmListUpdate.Update.Name = realm.Value.Name; - realmListUpdate.Update.CfgConfigsID = (int)realm.Value.GetConfigId(); - realmListUpdate.Update.CfgLanguagesID = 1; - - realmListUpdate.Deleting = false; - - realmList.Updates.Add(realmListUpdate); + RealmListUpdatePart state = new(); + state.WoWRealmAddress = (int)id.GetAddress(); + state.Deleting = true; + realmList.Updates.Add(state); } var jsonData = Encoding.UTF8.GetBytes("JSONRealmListUpdates:" + JsonSerializer.Serialize(realmList) + "\0"); - var compressedData = ZLib.Compress(jsonData); - - return BitConverter.GetBytes(jsonData.Length).Combine(compressedData); + return BitConverter.GetBytes(jsonData.Length).Combine(ZLib.Compress(jsonData)); } - public BattlenetRpcErrorCode JoinRealm(uint realmAddress, uint build, IPAddress clientAddress, byte[] clientSecret, Locale locale, string os, TimeSpan timezoneOffset, string accountName, Bgs.Protocol.GameUtilities.V1.ClientResponse response) + public BattlenetRpcErrorCode JoinRealm(uint realmAddress, uint build, IPAddress clientAddress, byte[] clientSecret, Locale locale, string os, TimeSpan timezoneOffset, string accountName, AccountTypes accountSecurityLevel, Bgs.Protocol.GameUtilities.V1.ClientResponse response) { Realm realm = GetRealm(new RealmId(realmAddress)); if (realm != null) { - if (realm.Flags.HasAnyFlag(RealmFlags.Offline) || realm.Build != build) + if (realm.PopulationLevel == RealmPopulationState.Offline || realm.Build != build || accountSecurityLevel < realm.AllowedSecurityLevel) return BattlenetRpcErrorCode.UserServerNotPermittedOnRealm; RealmListServerIPAddresses serverAddresses = new(); @@ -300,9 +317,7 @@ public class RealmManager : Singleton serverAddresses.Families.Add(addressFamily); var jsonData = Encoding.UTF8.GetBytes("JSONRealmListServerIPAddresses:" + JsonSerializer.Serialize(serverAddresses) + "\0"); - var compressedData = ZLib.Compress(jsonData); - - byte[] compressed = BitConverter.GetBytes(jsonData.Length).Combine(compressedData); + byte[] compressed = BitConverter.GetBytes(jsonData.Length).Combine(ZLib.Compress(jsonData)); byte[] serverSecret = new byte[0].GenerateRandomKey(32); byte[] keyData = clientSecret.Combine(serverSecret); @@ -310,16 +325,17 @@ public class RealmManager : Singleton PreparedStatement stmt = LoginDatabase.GetPreparedStatement(LoginStatements.UPD_BNET_GAME_ACCOUNT_LOGIN_INFO); stmt.AddValue(0, keyData); stmt.AddValue(1, clientAddress.ToString()); - stmt.AddValue(2, (byte)locale); - stmt.AddValue(3, os); - stmt.AddValue(4, (short)timezoneOffset.TotalMinutes); - stmt.AddValue(5, accountName); + stmt.AddValue(2, build); + stmt.AddValue(3, (byte)locale); + stmt.AddValue(4, os); + stmt.AddValue(5, (short)timezoneOffset.TotalMinutes); + stmt.AddValue(6, accountName); DB.Login.DirectExecute(stmt); Bgs.Protocol.Attribute attribute = new(); attribute.Name = "Param_RealmJoinTicket"; attribute.Value = new Bgs.Protocol.Variant(); - attribute.Value.BlobValue = Google.Protobuf.ByteString.CopyFrom(accountName, System.Text.Encoding.UTF8); + attribute.Value.BlobValue = Google.Protobuf.ByteString.CopyFrom(accountName, Encoding.UTF8); response.Attribute.Add(attribute); attribute = new Bgs.Protocol.Attribute(); @@ -339,13 +355,40 @@ public class RealmManager : Singleton return BattlenetRpcErrorCode.UtilServerUnknownRealm; } + RealmFlags ConvertLegacyRealmFlags(LegacyRealmFlags legacyRealmFlags) + { + RealmFlags realmFlags = RealmFlags.None; + if (legacyRealmFlags.HasAnyFlag(LegacyRealmFlags.VersionMismatch)) + realmFlags |= RealmFlags.VersionMismatch; + return realmFlags; + } + + RealmPopulationState ConvertLegacyPopulationState(LegacyRealmFlags legacyRealmFlags, float population) + { + if (legacyRealmFlags .HasAnyFlag(LegacyRealmFlags.Offline)) + return RealmPopulationState.Offline; + if (legacyRealmFlags.HasAnyFlag(LegacyRealmFlags.Recommended)) + return RealmPopulationState.Recommended; + if (legacyRealmFlags.HasAnyFlag(LegacyRealmFlags.New)) + return RealmPopulationState.New; + if (legacyRealmFlags.HasAnyFlag(LegacyRealmFlags.Full) || population > 0.95f) + return RealmPopulationState.Full; + if (population > 0.66f) + return RealmPopulationState.High; + if (population > 0.33f) + return RealmPopulationState.Medium; + return RealmPopulationState.Low; + } + public ICollection GetRealms() { return _realms.Values; } List GetSubRegions() { return _subRegions; } List _builds = new(); ConcurrentDictionary _realms = new(); + Dictionary _removedRealms = new(); List _subRegions = new(); Timer _updateTimer; + RealmId? _currentRealmId; } public class RealmBuildInfo diff --git a/Source/Framework/Web/Rest/Realmlist/RealmListRAFInfo.cs b/Source/Framework/Web/Rest/Realmlist/RealmListRAFInfo.cs new file mode 100644 index 000000000..3c254f5ec --- /dev/null +++ b/Source/Framework/Web/Rest/Realmlist/RealmListRAFInfo.cs @@ -0,0 +1,17 @@ +// Copyright (c) CypherCore All rights reserved. +// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information. + +using System.Text.Json.Serialization; +using Framework.Web.Rest.Realmlist; + +namespace Framework.Web.Rest.Realmlist +{ + internal class RealmListRAFInfo + { + [JsonPropertyName("wowRealmAddress")] + public int WowRealmAddress { get; set; } + + [JsonPropertyName("faction")] + public int Faction { get; set; } + } +} diff --git a/Source/Framework/Web/Rest/Realmlist/RealmListUpdate.cs b/Source/Framework/Web/Rest/Realmlist/RealmListUpdatePart.cs similarity index 77% rename from Source/Framework/Web/Rest/Realmlist/RealmListUpdate.cs rename to Source/Framework/Web/Rest/Realmlist/RealmListUpdatePart.cs index b4f12c49c..977a4785d 100644 --- a/Source/Framework/Web/Rest/Realmlist/RealmListUpdate.cs +++ b/Source/Framework/Web/Rest/Realmlist/RealmListUpdatePart.cs @@ -5,8 +5,11 @@ using System.Text.Json.Serialization; namespace Framework.Web { - public class RealmListUpdate + public class RealmListUpdatePart { + [JsonPropertyName("wowRealmAddress")] + public int WoWRealmAddress { get; set; } + [JsonPropertyName("update")] public RealmEntry Update { get; set; } = new RealmEntry(); diff --git a/Source/Framework/Web/Rest/Realmlist/RealmListUpdates.cs b/Source/Framework/Web/Rest/Realmlist/RealmListUpdates.cs index e74960ce6..35b549a0d 100644 --- a/Source/Framework/Web/Rest/Realmlist/RealmListUpdates.cs +++ b/Source/Framework/Web/Rest/Realmlist/RealmListUpdates.cs @@ -9,6 +9,6 @@ namespace Framework.Web public class RealmListUpdates { [JsonPropertyName("updates")] - public IList Updates { get; set; } = new List(); + public IList Updates { get; set; } = new List(); } } diff --git a/Source/Game/Accounts/AccountManager.cs b/Source/Game/Accounts/AccountManager.cs index 47016ef77..6e1c1dc5a 100644 --- a/Source/Game/Accounts/AccountManager.cs +++ b/Source/Game/Accounts/AccountManager.cs @@ -424,7 +424,7 @@ namespace Game while (result.NextRow()); Log.outDebug(LogFilter.Rbac, "AccountMgr:LoadRBAC: Loading default permissions"); - result = DB.Login.Query("SELECT secId, permissionId FROM rbac_default_permissions ORDER BY secId ASC"); + result = DB.Login.Query($"SELECT secId, permissionId FROM rbac_default_permissions WHERE (realmId = {Global.RealmMgr.GetCurrentRealmId().Index} OR realmId = -1) ORDER BY secId ASC"); if (result.IsEmpty()) { Log.outInfo(LogFilter.ServerLoading, "Loaded 0 default permission definitions. DB table `rbac_default_permissions` is empty."); diff --git a/Source/Game/Achievements/CriteriaHandler.cs b/Source/Game/Achievements/CriteriaHandler.cs index fc10ed5a7..b5ee77876 100644 --- a/Source/Game/Achievements/CriteriaHandler.cs +++ b/Source/Game/Achievements/CriteriaHandler.cs @@ -1439,7 +1439,10 @@ namespace Game.Achievements return false; break; case ModifierTreeType.ClientVersionEqualOrLessThan: // 33 - if (reqValue < Global.RealmMgr.GetMinorMajorBugfixVersionForBuild(Global.WorldMgr.GetRealm().Build)) + var currentRealm = Global.RealmMgr.GetCurrentRealm(); + if (currentRealm == null) + return false; + if (reqValue < Global.RealmMgr.GetMinorMajorBugfixVersionForBuild(currentRealm.Build)) return false; break; case ModifierTreeType.BattlePetTeamLevel: // 34 diff --git a/Source/Game/BattlePets/BattlePetManager.cs b/Source/Game/BattlePets/BattlePetManager.cs index e15d8bbcc..7145351d6 100644 --- a/Source/Game/BattlePets/BattlePetManager.cs +++ b/Source/Game/BattlePets/BattlePetManager.cs @@ -229,19 +229,20 @@ namespace Game.BattlePets pet.NameTimestamp = petsResult.Read(10); pet.PacketInfo.CreatureID = speciesEntry.CreatureID; - if (!petsResult.IsNull(12)) + if (!petsResult.IsNull(13)) { pet.DeclinedName = new(); for (byte i = 0; i < SharedConst.MaxDeclinedNameCases; ++i) - pet.DeclinedName.name[i] = petsResult.Read(12 + i); + pet.DeclinedName.name[i] = petsResult.Read(13 + i); } if (!ownerGuid.IsEmpty()) { BattlePetStruct.BattlePetOwnerInfo battlePetOwnerInfo = new(); battlePetOwnerInfo.Guid = ownerGuid; - battlePetOwnerInfo.PlayerVirtualRealm = Global.WorldMgr.GetVirtualRealmAddress(); - battlePetOwnerInfo.PlayerNativeRealm = Global.WorldMgr.GetVirtualRealmAddress(); + var ownerRealm = Global.RealmMgr.GetRealm(new Framework.Realm.RealmId(petsResult.Read(12))); + if (ownerRealm != null) + battlePetOwnerInfo.PlayerVirtualRealm = battlePetOwnerInfo.PlayerNativeRealm = ownerRealm.Id.GetAddress(); pet.PacketInfo.OwnerInfo = battlePetOwnerInfo; } @@ -293,7 +294,7 @@ namespace Game.BattlePets if (pair.Value.PacketInfo.OwnerInfo.HasValue) { stmt.AddValue(12, pair.Value.PacketInfo.OwnerInfo.Value.Guid.GetCounter()); - stmt.AddValue(13, Global.WorldMgr.GetRealmId().Index); + stmt.AddValue(13, Global.RealmMgr.GetCurrentRealmId().Index); } else { @@ -409,7 +410,7 @@ namespace Game.BattlePets { BattlePetStruct.BattlePetOwnerInfo battlePetOwnerInfo = new(); battlePetOwnerInfo.Guid = player.GetGUID(); - battlePetOwnerInfo.PlayerVirtualRealm = _owner.m_playerData.VirtualPlayerRealm; + battlePetOwnerInfo.PlayerVirtualRealm = player.m_playerData.VirtualPlayerRealm; battlePetOwnerInfo.PlayerNativeRealm = Global.WorldMgr.GetVirtualRealmAddress(); pet.PacketInfo.OwnerInfo = battlePetOwnerInfo; } diff --git a/Source/Game/BlackMarket/BlackMarketManager.cs b/Source/Game/BlackMarket/BlackMarketManager.cs index f0d7d31a7..a3cf32256 100644 --- a/Source/Game/BlackMarket/BlackMarketManager.cs +++ b/Source/Game/BlackMarket/BlackMarketManager.cs @@ -218,7 +218,7 @@ namespace Game.BlackMarket if (bidderAccId == 0) // Account exists return; - logGmTrade = Global.AccountMgr.HasPermission(bidderAccId, RBACPermissions.LogGmTrade, Global.WorldMgr.GetRealmId().Index); + logGmTrade = Global.AccountMgr.HasPermission(bidderAccId, RBACPermissions.LogGmTrade, Global.RealmMgr.GetCurrentRealmId().Index); if (logGmTrade && !Global.CharacterCacheStorage.GetCharacterNameByGuid(bidderGuid, out bidderName)) bidderName = Global.ObjectMgr.GetCypherString(CypherStrings.Unknown); diff --git a/Source/Game/Chat/Channels/ChannelManager.cs b/Source/Game/Chat/Channels/ChannelManager.cs index 5d0cb8b33..1f921d87a 100644 --- a/Source/Game/Chat/Channels/ChannelManager.cs +++ b/Source/Game/Chat/Channels/ChannelManager.cs @@ -207,7 +207,7 @@ namespace Game.Chat { ulong high = 0; high |= (ulong)HighGuid.ChatChannel << 58; - high |= (ulong)Global.WorldMgr.GetRealmId().Index << 42; + high |= (ulong)Global.RealmMgr.GetCurrentRealmId().Index << 42; high |= (ulong)(_team == Team.Alliance ? 3 : 5) << 4; ObjectGuid channelGuid = new(); @@ -224,9 +224,13 @@ namespace Game.Chat if (channelEntry.HasFlag(ChatChannelFlags.GlobalForTournament)) { - var category = CliDB.CfgCategoriesStorage.LookupByKey(Global.WorldMgr.GetRealm().Timezone); - if (category != null && category.HasFlag(CfgCategoriesFlags.Tournament)) - zoneId = 0; + 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); diff --git a/Source/Game/Chat/CommandHandler.cs b/Source/Game/Chat/CommandHandler.cs index acd16792b..7d315b23e 100644 --- a/Source/Game/Chat/CommandHandler.cs +++ b/Source/Game/Chat/CommandHandler.cs @@ -454,7 +454,7 @@ namespace Game.Chat if (target != null) target_ac_sec = target.GetSecurity(); else if (target_account != 0) - target_ac_sec = Global.AccountMgr.GetSecurity(target_account, (int)Global.WorldMgr.GetRealmId().Index); + target_ac_sec = Global.AccountMgr.GetSecurity(target_account, (int)Global.RealmMgr.GetCurrentRealmId().Index); else return true; // caller must report error for (target == NULL && target_account == 0) diff --git a/Source/Game/Chat/Commands/GMCommands.cs b/Source/Game/Chat/Commands/GMCommands.cs index e8d6cef41..2528c2af9 100644 --- a/Source/Game/Chat/Commands/GMCommands.cs +++ b/Source/Game/Chat/Commands/GMCommands.cs @@ -112,7 +112,7 @@ namespace Game.Chat // Get the accounts with GM Level >0 PreparedStatement stmt = LoginDatabase.GetPreparedStatement(LoginStatements.SEL_GM_ACCOUNTS); stmt.AddValue(0, (byte)AccountTypes.Moderator); - stmt.AddValue(1, Global.WorldMgr.GetRealm().Id.Index); + stmt.AddValue(1, Global.RealmMgr.GetCurrentRealmId().Index); SQLResult result = DB.Login.Query(stmt); if (!result.IsEmpty()) diff --git a/Source/Game/Chat/Commands/MiscCommands.cs b/Source/Game/Chat/Commands/MiscCommands.cs index f6093fc94..e4c700869 100644 --- a/Source/Game/Chat/Commands/MiscCommands.cs +++ b/Source/Game/Chat/Commands/MiscCommands.cs @@ -1250,7 +1250,7 @@ namespace Game.Chat // Query the prepared statement for login data stmt = LoginDatabase.GetPreparedStatement(LoginStatements.SEL_PINFO); - stmt.AddValue(0, Global.WorldMgr.GetRealm().Id.Index); + stmt.AddValue(0, Global.RealmMgr.GetCurrentRealmId().Index); stmt.AddValue(1, accId); SQLResult result0 = DB.Login.Query(stmt); diff --git a/Source/Game/Chat/Commands/RbacCommands.cs b/Source/Game/Chat/Commands/RbacCommands.cs index 9226e6889..5c7588c5d 100644 --- a/Source/Game/Chat/Commands/RbacCommands.cs +++ b/Source/Game/Chat/Commands/RbacCommands.cs @@ -230,7 +230,8 @@ namespace Game.Chat.Commands if (account.IsConnected()) return new RBACCommandData() { rbac = account.GetConnectedSession().GetRBACData(), needDelete = false }; - RBACData rbac = new(account.GetID(), account.GetName(), (int)Global.WorldMgr.GetRealmId().Index, (byte)Global.AccountMgr.GetSecurity(account.GetID(), (int)Global.WorldMgr.GetRealmId().Index)); + int realmId = (int)Global.RealmMgr.GetCurrentRealmId().Index; + RBACData rbac = new(account.GetID(), account.GetName(), realmId, (byte)Global.AccountMgr.GetSecurity(account.GetID(), realmId)); rbac.LoadFromDB(); return new RBACCommandData() { rbac = rbac, needDelete = true }; diff --git a/Source/Game/Chat/Commands/ServerCommands.cs b/Source/Game/Chat/Commands/ServerCommands.cs index 51f98d062..310f4d05d 100644 --- a/Source/Game/Chat/Commands/ServerCommands.cs +++ b/Source/Game/Chat/Commands/ServerCommands.cs @@ -26,15 +26,11 @@ namespace Game.Chat { string dbPortOutput; - ushort dbPort = 0; - SQLResult res = DB.Login.Query($"SELECT port FROM realmlist WHERE id = {Global.WorldMgr.GetRealmId().Index}"); - if (!res.IsEmpty()) - dbPort = res.Read(0); - - if (dbPort != 0) - dbPortOutput = $"Realmlist (Realm Id: {Global.WorldMgr.GetRealmId().Index}) configured in port {dbPort}"; + var currentRealm = Global.RealmMgr.GetCurrentRealm(); + if (currentRealm != null) + dbPortOutput = $"Realmlist (Realm Id: {currentRealm.Id.Index}) configured in port {currentRealm.Port}"; else - dbPortOutput = $"Realm Id: {Global.WorldMgr.GetRealmId().Index} not found in `realmlist` table. Please check your setup"; + dbPortOutput = $"Realm Id: {Global.RealmMgr.GetCurrentRealmId().Index} not found in `realmlist` table. Please check your setup"; DatabaseTypeFlags updateFlags = ConfigMgr.GetDefaultValue("Updates.EnableDatabases", DatabaseTypeFlags.None); if (updateFlags == 0) diff --git a/Source/Game/Chat/Commands/TicketCommands.cs b/Source/Game/Chat/Commands/TicketCommands.cs index 90a52a2ab..06a9062a7 100644 --- a/Source/Game/Chat/Commands/TicketCommands.cs +++ b/Source/Game/Chat/Commands/TicketCommands.cs @@ -241,7 +241,7 @@ namespace Game.Chat.Commands ObjectGuid targetGuid = Global.CharacterCacheStorage.GetCharacterGuidByName(targetName); uint accountId = Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(targetGuid); // Target must exist and have administrative rights - if (!Global.AccountMgr.HasPermission(accountId, RBACPermissions.CommandsBeAssignedTicket, Global.WorldMgr.GetRealm().Id.Index)) + if (!Global.AccountMgr.HasPermission(accountId, RBACPermissions.CommandsBeAssignedTicket, Global.RealmMgr.GetCurrentRealmId().Index)) { handler.SendSysMessage(CypherStrings.CommandTicketassignerrorA); return true; @@ -264,7 +264,7 @@ namespace Game.Chat.Commands } // Assign ticket - ticket.SetAssignedTo(targetGuid, Global.AccountMgr.IsAdminAccount(Global.AccountMgr.GetSecurity(accountId, (int)Global.WorldMgr.GetRealm().Id.Index))); + ticket.SetAssignedTo(targetGuid, Global.AccountMgr.IsAdminAccount(Global.AccountMgr.GetSecurity(accountId, (int)Global.RealmMgr.GetCurrentRealmId().Index))); ticket.SaveToDB(); string msg = ticket.FormatViewMessageString(handler, null, targetName, null, null); @@ -411,7 +411,7 @@ namespace Game.Chat.Commands { ObjectGuid guid = ticket.GetAssignedToGUID(); uint accountId = Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(guid); - security = Global.AccountMgr.GetSecurity(accountId, (int)Global.WorldMgr.GetRealm().Id.Index); + security = Global.AccountMgr.GetSecurity(accountId, (int)Global.RealmMgr.GetCurrentRealmId().Index); } // Check security diff --git a/Source/Game/Conditions/ConditionManager.cs b/Source/Game/Conditions/ConditionManager.cs index 88701d6e0..acb2d4e82 100644 --- a/Source/Game/Conditions/ConditionManager.cs +++ b/Source/Game/Conditions/ConditionManager.cs @@ -2846,7 +2846,7 @@ namespace Game DateTime localTime = GameTime.GetDateAndTime(); return localTime.Hour * Time.Minute + localTime.Minute; case WorldStateExpressionFunctions.Region: - return Global.WorldMgr.GetRealmId().Region; + return Global.RealmMgr.GetCurrentRealmId().Region; case WorldStateExpressionFunctions.ClockHour: int currentHour = GameTime.GetDateAndTime().Hour + 1; return currentHour <= 12 ? (currentHour != 0 ? currentHour : 12) : currentHour - 12; @@ -2863,7 +2863,7 @@ namespace Game case WorldStateExpressionFunctions.WeekNumber: long now = GameTime.GetGameTime(); uint raidOrigin = 1135695600; - Cfg_RegionsRecord region = CliDB.CfgRegionsStorage.LookupByKey(Global.WorldMgr.GetRealmId().Region); + Cfg_RegionsRecord region = CliDB.CfgRegionsStorage.LookupByKey(Global.RealmMgr.GetCurrentRealmId().Region); if (region != null) raidOrigin = region.Raidorigin; diff --git a/Source/Game/Entities/Object/ObjectGuid.cs b/Source/Game/Entities/Object/ObjectGuid.cs index db2dfaa2e..d23950018 100644 --- a/Source/Game/Entities/Object/ObjectGuid.cs +++ b/Source/Game/Entities/Object/ObjectGuid.cs @@ -576,7 +576,7 @@ namespace Game.Entities if (realmId != 0) return realmId; - return Global.WorldMgr.GetRealmId().Index; + return Global.RealmMgr.GetCurrentRealmId().Index; } } diff --git a/Source/Game/Entities/Player/Player.DB.cs b/Source/Game/Entities/Player/Player.DB.cs index 1794c1cd5..112360da9 100644 --- a/Source/Game/Entities/Player/Player.DB.cs +++ b/Source/Game/Entities/Player/Player.DB.cs @@ -3835,7 +3835,11 @@ namespace Game.Entities stmt.AddValue(index++, ss.ToString()); stmt.AddValue(index++, m_activePlayerData.MultiActionBars); - stmt.AddValue(index++, Global.RealmMgr.GetMinorMajorBugfixVersionForBuild(Global.WorldMgr.GetRealm().Build)); + var currentRealm = Global.RealmMgr.GetCurrentRealm(); + if (currentRealm != null) + stmt.AddValue(index++, Global.RealmMgr.GetMinorMajorBugfixVersionForBuild(currentRealm.Build)); + else + stmt.AddValue(index++, 0); } else { @@ -3992,7 +3996,11 @@ namespace Game.Entities stmt.AddValue(index++, GetHonorLevel()); stmt.AddValue(index++, m_activePlayerData.RestInfo[(int)RestTypes.Honor].StateID); stmt.AddValue(index++, finiteAlways(_restMgr.GetRestBonus(RestTypes.Honor))); - stmt.AddValue(index++, Global.RealmMgr.GetMinorMajorBugfixVersionForBuild(Global.WorldMgr.GetRealm().Build)); + var currentRealm = Global.RealmMgr.GetCurrentRealm(); + if (currentRealm != null) + stmt.AddValue(index++, Global.RealmMgr.GetMinorMajorBugfixVersionForBuild(currentRealm.Build)); + else + stmt.AddValue(index++, 0); // Index stmt.AddValue(index, GetGUID().GetCounter()); @@ -4054,17 +4062,19 @@ namespace Game.Entities GetSession().GetCollectionMgr().SaveAccountItemAppearances(loginTransaction); GetSession().GetCollectionMgr().SaveAccountTransmogIllusions(loginTransaction); + var currentRealmId = Global.RealmMgr.GetCurrentRealmId(); + stmt = LoginDatabase.GetPreparedStatement(LoginStatements.DEL_BNET_LAST_PLAYER_CHARACTERS); stmt.AddValue(0, GetSession().GetAccountId()); - stmt.AddValue(1, Global.WorldMgr.GetRealmId().Region); - stmt.AddValue(2, Global.WorldMgr.GetRealmId().Site); + stmt.AddValue(1, currentRealmId.Region); + stmt.AddValue(2, currentRealmId.Site); loginTransaction.Append(stmt); stmt = LoginDatabase.GetPreparedStatement(LoginStatements.INS_BNET_LAST_PLAYER_CHARACTERS); stmt.AddValue(0, GetSession().GetAccountId()); - stmt.AddValue(1, Global.WorldMgr.GetRealmId().Region); - stmt.AddValue(2, Global.WorldMgr.GetRealmId().Site); - stmt.AddValue(3, Global.WorldMgr.GetRealmId().Index); + stmt.AddValue(1, currentRealmId.Region); + stmt.AddValue(2, currentRealmId.Site); + stmt.AddValue(3, currentRealmId.Index); stmt.AddValue(4, GetName()); stmt.AddValue(5, GetGUID().GetCounter()); stmt.AddValue(6, GameTime.GetGameTime()); @@ -4562,12 +4572,12 @@ namespace Game.Entities stmt = LoginDatabase.GetPreparedStatement(LoginStatements.DEL_BATTLE_PET_DECLINED_NAME_BY_OWNER); stmt.AddValue(0, guid); - stmt.AddValue(1, Global.WorldMgr.GetRealmId().Index); + stmt.AddValue(1, Global.RealmMgr.GetCurrentRealmId().Index); loginTransaction.Append(stmt); stmt = LoginDatabase.GetPreparedStatement(LoginStatements.DEL_BATTLE_PETS_BY_OWNER); stmt.AddValue(0, guid); - stmt.AddValue(1, Global.WorldMgr.GetRealmId().Index); + stmt.AddValue(1, Global.RealmMgr.GetCurrentRealmId().Index); loginTransaction.Append(stmt); Corpse.DeleteFromDB(playerGuid, trans); diff --git a/Source/Game/Globals/ObjectManager.cs b/Source/Game/Globals/ObjectManager.cs index 75f82e588..28bd332cf 100644 --- a/Source/Game/Globals/ObjectManager.cs +++ b/Source/Game/Globals/ObjectManager.cs @@ -60,9 +60,13 @@ namespace Game static CfgCategoriesCharsets GetRealmLanguageType(bool create) { - Cfg_CategoriesRecord category = CliDB.CfgCategoriesStorage.LookupByKey(Global.WorldMgr.GetRealm().Timezone); - if (category != null) - return create ? category.GetCreateCharsetMask() : category.GetExistingCharsetMask(); + var currentRealm = Global.RealmMgr.GetCurrentRealm(); + if (currentRealm != null) + { + Cfg_CategoriesRecord category = CliDB.CfgCategoriesStorage.LookupByKey(currentRealm.Timezone); + if (category != null) + return create ? category.GetCreateCharsetMask() : category.GetExistingCharsetMask(); + } return create ? CfgCategoriesCharsets.English : CfgCategoriesCharsets.Any; // basic-Latin at create, any at login } diff --git a/Source/Game/Handlers/AuthenticationHandler.cs b/Source/Game/Handlers/AuthenticationHandler.cs index 5bff6d9cb..3740d53c3 100644 --- a/Source/Game/Handlers/AuthenticationHandler.cs +++ b/Source/Game/Handlers/AuthenticationHandler.cs @@ -22,13 +22,15 @@ namespace Game response.SuccessInfo = new AuthResponse.AuthSuccessInfo(); response.SuccessInfo.ActiveExpansionLevel = (byte)GetExpansion(); response.SuccessInfo.AccountExpansionLevel = (byte)GetAccountExpansion(); - response.SuccessInfo.VirtualRealmAddress = Global.WorldMgr.GetVirtualRealmAddress(); response.SuccessInfo.Time = (uint)GameTime.GetGameTime(); - var realm = Global.WorldMgr.GetRealm(); - // Send current home realm. Also there is no need to send it later in realm queries. - response.SuccessInfo.VirtualRealms.Add(new VirtualRealmInfo(realm.Id.GetAddress(), true, false, realm.Name, realm.NormalizedName)); + var currentRealm = Global.RealmMgr.GetCurrentRealm(); + if(currentRealm != null) + { + response.SuccessInfo.VirtualRealmAddress = currentRealm.Id.GetAddress(); + response.SuccessInfo.VirtualRealms.Add(new VirtualRealmInfo(currentRealm.Id.GetAddress(), true, false, currentRealm.Name, currentRealm.NormalizedName)); + } if (HasPermission(RBACPermissions.UseCharacterTemplates)) foreach (var templ in Global.CharacterTemplateDataStorage.GetCharacterTemplates().Values) diff --git a/Source/Game/Handlers/CharacterHandler.cs b/Source/Game/Handlers/CharacterHandler.cs index 4ac7b6ab4..cd701f993 100644 --- a/Source/Game/Handlers/CharacterHandler.cs +++ b/Source/Game/Handlers/CharacterHandler.cs @@ -608,7 +608,7 @@ namespace Game stmt = LoginDatabase.GetPreparedStatement(LoginStatements.REP_REALM_CHARACTERS); stmt.AddValue(0, createInfo.CharCount); stmt.AddValue(1, GetAccountId()); - stmt.AddValue(2, Global.WorldMgr.GetRealm().Id.Index); + stmt.AddValue(2, Global.RealmMgr.GetCurrentRealmId().Index); loginTransaction.Append(stmt); DB.Login.CommitTransaction(loginTransaction); diff --git a/Source/Game/Handlers/HotfixHandler.cs b/Source/Game/Handlers/HotfixHandler.cs index 9dd37788b..e170d5efd 100644 --- a/Source/Game/Handlers/HotfixHandler.cs +++ b/Source/Game/Handlers/HotfixHandler.cs @@ -49,7 +49,7 @@ namespace Game void SendAvailableHotfixes() { AvailableHotfixes availableHotfixes = new(); - availableHotfixes.VirtualRealmAddress = Global.WorldMgr.GetRealmId().GetAddress(); + availableHotfixes.VirtualRealmAddress = Global.WorldMgr.GetVirtualRealmAddress(); foreach (var (_, push) in Global.DB2Mgr.GetHotfixData()) { diff --git a/Source/Game/Handlers/QueryHandler.cs b/Source/Game/Handlers/QueryHandler.cs index a837e4f71..87d8b525d 100644 --- a/Source/Game/Handlers/QueryHandler.cs +++ b/Source/Game/Handlers/QueryHandler.cs @@ -330,12 +330,14 @@ namespace Game RealmQueryResponse realmQueryResponse = new(); realmQueryResponse.VirtualRealmAddress = queryRealmName.VirtualRealmAddress; - RealmId realmHandle = new(queryRealmName.VirtualRealmAddress); - if (Global.RealmMgr.GetRealmNames(realmHandle, out realmQueryResponse.NameInfo.RealmNameActual, out realmQueryResponse.NameInfo.RealmNameNormalized)) + var realm = Global.RealmMgr.GetRealm(new RealmId(queryRealmName.VirtualRealmAddress)); + if (realm != null) { realmQueryResponse.LookupState = (byte)ResponseCodes.Success; realmQueryResponse.NameInfo.IsInternalRealm = false; realmQueryResponse.NameInfo.IsLocal = queryRealmName.VirtualRealmAddress == Global.WorldMgr.GetVirtualRealmAddress(); + realmQueryResponse.NameInfo.RealmNameActual = realm.Name; + realmQueryResponse.NameInfo.RealmNameNormalized = realm.NormalizedName; } else realmQueryResponse.LookupState = (byte)ResponseCodes.Failure; diff --git a/Source/Game/Handlers/SocialHandler.cs b/Source/Game/Handlers/SocialHandler.cs index 3ea00eddc..f18d0792c 100644 --- a/Source/Game/Handlers/SocialHandler.cs +++ b/Source/Game/Handlers/SocialHandler.cs @@ -270,7 +270,7 @@ namespace Game } // When not found, consult database - GetQueryProcessor().AddCallback(Global.AccountMgr.GetSecurityAsync(friendCharacterInfo.AccountId, (int)Global.WorldMgr.GetRealmId().Index, friendSecurity => + GetQueryProcessor().AddCallback(Global.AccountMgr.GetSecurityAsync(friendCharacterInfo.AccountId, (int)Global.RealmMgr.GetCurrentRealmId().Index, friendSecurity => { if (!Global.AccountMgr.IsPlayerAccount((AccountTypes)friendSecurity)) { @@ -280,16 +280,6 @@ namespace Game processFriendRequest(); })); - - - - - - - - - - } [WorldPacketHandler(ClientOpcodes.DelFriend)] diff --git a/Source/Game/Networking/PacketLog.cs b/Source/Game/Networking/PacketLog.cs index 18d735508..01c835f27 100644 --- a/Source/Game/Networking/PacketLog.cs +++ b/Source/Game/Networking/PacketLog.cs @@ -24,7 +24,11 @@ public class PacketLog writer.Write(Encoding.ASCII.GetBytes("PKT")); writer.Write((ushort)769); writer.Write(Encoding.ASCII.GetBytes("T")); - writer.Write(Global.WorldMgr.GetRealm().Build); + var currentRealm = Global.RealmMgr.GetCurrentRealm(); + if (currentRealm != null) + writer.Write(currentRealm.Build); + else + writer.Write(0); writer.Write(Encoding.ASCII.GetBytes("enUS")); writer.Write(new byte[40]);//SessionKey writer.Write((uint)GameTime.GetGameTime()); diff --git a/Source/Game/Networking/Packets/PartyPackets.cs b/Source/Game/Networking/Packets/PartyPackets.cs index 4adf83080..dce0df669 100644 --- a/Source/Game/Networking/Packets/PartyPackets.cs +++ b/Source/Game/Networking/Packets/PartyPackets.cs @@ -76,8 +76,9 @@ namespace Game.Networking.Packets ProposedRoles = (byte)proposedRoles; - var realm = Global.WorldMgr.GetRealm(); - InviterRealm = new VirtualRealmInfo(realm.Id.GetAddress(), true, false, realm.Name, realm.NormalizedName); + var realm = Global.RealmMgr.GetRealm(new Framework.Realm.RealmId(inviter.m_playerData.VirtualPlayerRealm)); + if (realm != null) + InviterRealm = new VirtualRealmInfo(realm.Id.GetAddress(), true, false, realm.Name, realm.NormalizedName); } public override void Write() @@ -949,7 +950,7 @@ namespace Game.Networking.Packets public override void Read() { bool hasPartyIndex = _worldPacket.HasBit(); - RestrictTo = (RestrictPingsTo)_worldPacket.ReadInt32(); + RestrictTo = (RestrictPingsTo)_worldPacket.ReadInt32(); if (hasPartyIndex) PartyIndex = _worldPacket.ReadUInt8(); } diff --git a/Source/Game/Networking/WorldSocket.cs b/Source/Game/Networking/WorldSocket.cs index 9c39518a2..38e971661 100644 --- a/Source/Game/Networking/WorldSocket.cs +++ b/Source/Game/Networking/WorldSocket.cs @@ -453,7 +453,7 @@ namespace Game.Networking { // Get the account information from the realmd database PreparedStatement stmt = LoginDatabase.GetPreparedStatement(LoginStatements.SEL_ACCOUNT_INFO_BY_NAME); - stmt.AddValue(0, Global.WorldMgr.GetRealm().Id.Index); + stmt.AddValue(0, Global.RealmMgr.GetCurrentRealmId().Index); stmt.AddValue(1, authSession.RealmJoinTicket); _queryProcessor.AddCallback(DB.Login.AsyncQuery(stmt).WithCallback(HandleAuthSessionCallback, authSession)); @@ -469,17 +469,17 @@ namespace Game.Networking return; } - RealmBuildInfo buildInfo = Global.RealmMgr.GetBuildInfo(Global.WorldMgr.GetRealm().Build); + AccountInfo account = new(result.GetFields()); + + RealmBuildInfo buildInfo = Global.RealmMgr.GetBuildInfo(account.game.Build); if (buildInfo == null) { SendAuthResponseError(BattlenetRpcErrorCode.BadVersion); - Log.outError(LogFilter.Network, $"WorldSocket.HandleAuthSessionCallback: Missing auth seed for realm build {Global.WorldMgr.GetRealm().Build} ({GetRemoteIpAddress()})."); + Log.outError(LogFilter.Network, $"WorldSocket.HandleAuthSessionCallback: Missing auth seed for realm build {account.game.Build} ({GetRemoteIpAddress()})."); CloseSocket(); return; } - AccountInfo account = new(result.GetFields()); - // For hook purposes, we get Remoteaddress at this point. var address = GetRemoteIpAddress(); @@ -556,11 +556,11 @@ namespace Game.Networking return; } - if (authSession.RealmID != Global.WorldMgr.GetRealm().Id.Index) + if (authSession.RealmID != Global.RealmMgr.GetCurrentRealmId().Index) { SendAuthResponseError(BattlenetRpcErrorCode.Denied); Log.outError(LogFilter.Network, "WorldSocket.HandleAuthSession: Client {0} requested connecting with realm id {1} but this realm has id {2} set in config.", - GetRemoteIpAddress().ToString(), authSession.RealmID, Global.WorldMgr.GetRealm().Id.Index); + GetRemoteIpAddress().ToString(), authSession.RealmID, Global.RealmMgr.GetCurrentRealmId().Index); CloseSocket(); return; } @@ -648,7 +648,7 @@ namespace Game.Networking Global.ScriptMgr.OnAccountLogin(account.game.Id); _worldSession = new WorldSession(account.game.Id, authSession.RealmJoinTicket, account.battleNet.Id, this, account.game.Security, (Expansion)account.game.Expansion, - mutetime, account.game.OS, account.game.TimezoneOffset, account.battleNet.Locale, account.game.Recruiter, account.game.IsRectuiter); + mutetime, account.game.OS, account.game.TimezoneOffset, account.game.Build, account.game.Locale, account.game.Recruiter, account.game.IsRectuiter); // Initialize Warden system only if it is enabled by config //if (wardenActive) @@ -835,9 +835,9 @@ namespace Game.Networking { public AccountInfo(SQLFields fields) { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 - // SELECT a.id, a.session_key, ba.last_ip, ba.locked, ba.lock_country, a.expansion, a.mutetime, ba.locale, a.recruiter, a.os, a.timezone_offset, ba.id, aa.SecurityLevel, - // 13 14 15 + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 + // SELECT a.id, a.session_key, ba.last_ip, ba.locked, ba.lock_country, a.expansion, a.mutetime, a.client_build, a.locale, a.recruiter, a.os, a.timezone_offset, ba.id, aa.SecurityLevel, + // 14 15 16 // bab.unbandate > UNIX_TIMESTAMP() OR bab.unbandate = bab.bandate, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, r.id // FROM account a LEFT JOIN battlenet_accounts ba ON a.battlenet_account = ba.id LEFT JOIN account_access aa ON a.id = aa.AccountID AND aa.RealmID IN (-1, ?) // LEFT JOIN battlenet_account_bans bab ON ba.id = bab.id LEFT JOIN account_banned ab ON a.id = ab.id LEFT JOIN account r ON a.id = r.recruiter @@ -849,18 +849,19 @@ namespace Game.Networking battleNet.LockCountry = fields.Read(4); game.Expansion = fields.Read(5); game.MuteTime = fields.Read(6); - battleNet.Locale = (Locale)fields.Read(7); - game.Recruiter = fields.Read(8); - game.OS = fields.Read(9); - game.TimezoneOffset = TimeSpan.FromMinutes(fields.Read(10)); - battleNet.Id = fields.Read(11); - game.Security = (AccountTypes)fields.Read(12); - battleNet.IsBanned = fields.Read(13) != 0; - game.IsBanned = fields.Read(14) != 0; - game.IsRectuiter = fields.Read(15) != 0; + game.Build = fields.Read(7); + game.Locale = (Locale)fields.Read(8); + game.Recruiter = fields.Read(9); + game.OS = fields.Read(10); + game.TimezoneOffset = TimeSpan.FromMinutes(fields.Read(11)); + battleNet.Id = fields.Read(12); + game.Security = (AccountTypes)fields.Read(13); + battleNet.IsBanned = fields.Read(14) != 0; + game.IsBanned = fields.Read(15) != 0; + game.IsRectuiter = fields.Read(16) != 0; - if (battleNet.Locale >= Locale.Total) - battleNet.Locale = Locale.enUS; + if (game.Locale >= Locale.Total) + game.Locale = Locale.enUS; } public bool IsBanned() { return battleNet.IsBanned || game.IsBanned; } @@ -874,7 +875,6 @@ namespace Game.Networking public bool IsLockedToIP; public string LastIP; public string LockCountry; - public Locale Locale; public bool IsBanned; } @@ -884,6 +884,8 @@ namespace Game.Networking public byte[] KeyData; public byte Expansion; public long MuteTime; + public uint Build; + public Locale Locale; public uint Recruiter; public string OS; public TimeSpan TimezoneOffset; diff --git a/Source/Game/Server/WorldSession.cs b/Source/Game/Server/WorldSession.cs index 1a6600f09..0f5243ea5 100644 --- a/Source/Game/Server/WorldSession.cs +++ b/Source/Game/Server/WorldSession.cs @@ -25,7 +25,7 @@ namespace Game { public partial class WorldSession : IDisposable { - public WorldSession(uint id, string name, uint battlenetAccountId, WorldSocket sock, AccountTypes sec, Expansion expansion, long mute_time, string os, TimeSpan timezoneOffset, Locale locale, uint recruiter, bool isARecruiter) + public WorldSession(uint id, string name, uint battlenetAccountId, WorldSocket sock, AccountTypes sec, Expansion expansion, long mute_time, string os, TimeSpan timezoneOffset, uint build, Locale locale, uint recruiter, bool isARecruiter) { m_muteTime = mute_time; AntiDOS = new DosProtection(this); @@ -37,6 +37,7 @@ namespace Game m_accountExpansion = expansion; m_expansion = (Expansion)Math.Min((byte)expansion, WorldConfig.GetIntValue(WorldCfg.Expansion)); _os = os; + _clientBuild = build; m_sessionDbcLocale = Global.WorldMgr.GetAvailableDbcLocale(locale); m_sessionDbLocaleIndex = locale; _timezoneOffset = timezoneOffset; @@ -477,7 +478,10 @@ namespace Game public void SendConnectToInstance(ConnectToSerial serial) { - var instanceAddress = Global.WorldMgr.GetRealm().GetAddressForClient(System.Net.IPAddress.Parse(GetRemoteAddress())); + System.Net.IPAddress instanceAddress = null; + var currentRealm = Global.RealmMgr.GetCurrentRealm(); + if (currentRealm != null) + instanceAddress = currentRealm.GetAddressForClient(System.Net.IPAddress.Parse(GetRemoteAddress())); _instanceConnectKey.AccountId = GetAccountId(); _instanceConnectKey.connectionType = ConnectionType.Instance; @@ -489,15 +493,18 @@ namespace Game connectTo.Payload.Port = (ushort)WorldConfig.GetIntValue(WorldCfg.PortInstance); connectTo.Con = (byte)ConnectionType.Instance; - if (instanceAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) + if (instanceAddress != null) { - connectTo.Payload.Where.IPv4 = instanceAddress.GetAddressBytes(); - connectTo.Payload.Where.Type = ConnectTo.AddressType.IPv4; - } - else - { - connectTo.Payload.Where.IPv6 = instanceAddress.GetAddressBytes(); - connectTo.Payload.Where.Type = ConnectTo.AddressType.IPv6; + if (instanceAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) + { + connectTo.Payload.Where.IPv4 = instanceAddress.GetAddressBytes(); + connectTo.Payload.Where.Type = ConnectTo.AddressType.IPv4; + } + else + { + connectTo.Payload.Where.IPv6 = instanceAddress.GetAddressBytes(); + connectTo.Payload.Where.Type = ConnectTo.AddressType.IPv6; + } } SendPacket(connectTo); @@ -678,6 +685,7 @@ namespace Game public Expansion GetAccountExpansion() { return m_accountExpansion; } public Expansion GetExpansion() { return m_expansion; } public string GetOS() { return _os; } + public uint GetClientBuild() { return _clientBuild; } public void SetInQueue(bool state) { m_inQueue = state; } public bool IsLogingOut() { return _logoutTime != 0 || m_playerLogout; } @@ -741,9 +749,9 @@ namespace Game AccountTypes secLevel = GetSecurity(); Log.outDebug(LogFilter.Rbac, "WorldSession.LoadPermissions [AccountId: {0}, Name: {1}, realmId: {2}, secLevel: {3}]", - id, _accountName, Global.WorldMgr.GetRealm().Id.Index, secLevel); + id, _accountName, Global.RealmMgr.GetCurrentRealmId().Index, secLevel); - _RBACData = new RBACData(id, _accountName, (int)Global.WorldMgr.GetRealm().Id.Index, (byte)secLevel); + _RBACData = new RBACData(id, _accountName, (int)Global.RealmMgr.GetCurrentRealmId().Index, (byte)secLevel); _RBACData.LoadFromDB(); } @@ -753,9 +761,9 @@ namespace Game AccountTypes secLevel = GetSecurity(); Log.outDebug(LogFilter.Rbac, "WorldSession.LoadPermissions [AccountId: {0}, Name: {1}, realmId: {2}, secLevel: {3}]", - id, _accountName, Global.WorldMgr.GetRealm().Id.Index, secLevel); + id, _accountName, Global.RealmMgr.GetCurrentRealmId().Index, secLevel); - _RBACData = new RBACData(id, _accountName, (int)Global.WorldMgr.GetRealm().Id.Index, (byte)secLevel); + _RBACData = new RBACData(id, _accountName, (int)Global.RealmMgr.GetCurrentRealmId().Index, (byte)secLevel); return _RBACData.LoadFromDBAsync(); } @@ -839,7 +847,7 @@ namespace Game bool hasPermission = _RBACData.HasPermission(permission); Log.outDebug(LogFilter.Rbac, "WorldSession:HasPermission [AccountId: {0}, Name: {1}, realmId: {2}]", - _RBACData.GetId(), _RBACData.GetName(), Global.WorldMgr.GetRealm().Id.Index); + _RBACData.GetId(), _RBACData.GetName(), Global.RealmMgr.GetCurrentRealmId().Index); return hasPermission; } @@ -847,7 +855,7 @@ namespace Game public void InvalidateRBACData() { Log.outDebug(LogFilter.Rbac, "WorldSession:Invalidaterbac:RBACData [AccountId: {0}, Name: {1}, realmId: {2}]", - _RBACData.GetId(), _RBACData.GetName(), Global.WorldMgr.GetRealm().Id.Index); + _RBACData.GetId(), _RBACData.GetName(), Global.RealmMgr.GetCurrentRealmId().Index); _RBACData = null; } @@ -944,6 +952,7 @@ namespace Game Expansion m_accountExpansion; Expansion m_expansion; string _os; + uint _clientBuild; uint expireTime; bool forceExit; @@ -1130,7 +1139,7 @@ namespace Game stmt = LoginDatabase.GetPreparedStatement(LoginStatements.SEL_BATTLE_PETS); stmt.AddValue(0, battlenetAccountId); - stmt.AddValue(1, Global.WorldMgr.GetRealmId().Index); + stmt.AddValue(1, Global.RealmMgr.GetCurrentRealmId().Index); SetQuery(AccountInfoQueryLoad.BattlePets, stmt); stmt = LoginDatabase.GetPreparedStatement(LoginStatements.SEL_BATTLE_PET_SLOTS); diff --git a/Source/Game/Services/GameUtilitiesService.cs b/Source/Game/Services/GameUtilitiesService.cs index 071976110..49b023f45 100644 --- a/Source/Game/Services/GameUtilitiesService.cs +++ b/Source/Game/Services/GameUtilitiesService.cs @@ -76,7 +76,7 @@ namespace Game if (subRegion != null) subRegionId = subRegion.StringValue; - var compressed = Global.RealmMgr.GetRealmList(Global.WorldMgr.GetRealm().Build, subRegionId); + var compressed = Global.RealmMgr.GetRealmList(GetClientBuild(), GetSecurity(), subRegionId); if (compressed.Empty()) return BattlenetRpcErrorCode.UtilServerFailedToSerializeResponse; @@ -112,8 +112,8 @@ namespace Game { var realmAddress = Params.LookupByKey("Param_RealmAddress"); if (realmAddress != null) - return Global.RealmMgr.JoinRealm((uint)realmAddress.UintValue, Global.WorldMgr.GetRealm().Build, System.Net.IPAddress.Parse(GetRemoteAddress()), GetRealmListSecret(), - GetSessionDbcLocale(), GetOS(), GetTimezoneOffset(), GetAccountName(), response); + return Global.RealmMgr.JoinRealm((uint)realmAddress.UintValue, GetClientBuild(), System.Net.IPAddress.Parse(GetRemoteAddress()), GetRealmListSecret(), + GetSessionDbcLocale(), GetOS(), GetTimezoneOffset(), GetAccountName(), GetSecurity(), response); return BattlenetRpcErrorCode.Ok; } diff --git a/Source/Game/World/WorldManager.cs b/Source/Game/World/WorldManager.cs index 690872f90..6f097542e 100644 --- a/Source/Game/World/WorldManager.cs +++ b/Source/Game/World/WorldManager.cs @@ -43,8 +43,6 @@ namespace Game m_allowedSecurityLevel = AccountTypes.Player; - _realm = new Realm(); - _worldUpdateTime = new WorldUpdateTime(); _warnShutdownTime = GameTime.GetGameTime(); } @@ -79,12 +77,9 @@ namespace Game public void LoadDBAllowedSecurityLevel() { - PreparedStatement stmt = LoginDatabase.GetPreparedStatement(LoginStatements.SEL_REALMLIST_SECURITY_LEVEL); - stmt.AddValue(0, (int)_realm.Id.Index); - SQLResult result = DB.Login.Query(stmt); - - if (!result.IsEmpty()) - SetPlayerSecurityLimit((AccountTypes)result.Read(0)); + var currentRealm = Global.RealmMgr.GetCurrentRealm(); + if (currentRealm != null) + SetPlayerSecurityLimit(currentRealm.AllowedSecurityLevel); } public void SetPlayerSecurityLimit(AccountTypes _sec) @@ -256,8 +251,13 @@ namespace Game { float popu = GetActiveSessionCount(); // updated number of users on the server popu /= pLimit; - popu *= 2; - Log.outInfo(LogFilter.Server, "Server Population ({0}).", popu); + + PreparedStatement stmt = LoginDatabase.GetPreparedStatement(LoginStatements.UPD_REALM_POPULATION); + stmt.AddValue(0, popu); + stmt.AddValue(1, Global.RealmMgr.GetCurrentRealmId().Index); + DB.Login.Execute(stmt); + + Log.outInfo(LogFilter.Server, $"Server Population ({popu})."); } } @@ -381,9 +381,7 @@ namespace Game public bool SetInitialWorldSettings() { - LoadRealmInfo(); - - Log.SetRealmId(_realm.Id.Index); + Log.SetRealmId(Global.RealmMgr.GetCurrentRealmId().Index); LoadConfigSettings(); @@ -415,7 +413,7 @@ namespace Game RealmType server_type = IsFFAPvPRealm() ? RealmType.PVP : (RealmType)WorldConfig.GetIntValue(WorldCfg.GameType); uint realm_zone = WorldConfig.GetUIntValue(WorldCfg.RealmZone); - DB.Login.Execute("UPDATE realmlist SET icon = {0}, timezone = {1} WHERE id = '{2}'", (byte)server_type, realm_zone, _realm.Id.Index); // One-time query + DB.Login.Execute($"UPDATE realmlist SET icon = {(byte)server_type}, timezone = {realm_zone} WHERE id = '{Global.RealmMgr.GetCurrentRealmId().Index}'"); // One-time query Log.outInfo(LogFilter.ServerLoading, "Initialize DataStorage..."); // Load DB2s @@ -1036,7 +1034,7 @@ namespace Game Log.outInfo(LogFilter.ServerLoading, "Initialize game time and timers"); GameTime.UpdateGameTimers(); - DB.Login.Execute("INSERT INTO uptime (realmid, starttime, uptime, revision) VALUES({0}, {1}, 0, '{2}')", _realm.Id.Index, GameTime.GetStartTime(), ""); // One-time query + DB.Login.Execute($"INSERT INTO uptime (realmid, starttime, uptime, revision) VALUES({Global.RealmMgr.GetCurrentRealmId().Index}, {GameTime.GetStartTime()}, 0, '{""}')"); // One-time query m_timers[WorldTimers.Auctions].SetInterval(Time.Minute * Time.InMilliseconds); m_timers[WorldTimers.AuctionsPending].SetInterval(250); @@ -1307,7 +1305,7 @@ namespace Game m_Autobroadcasts.Clear(); PreparedStatement stmt = LoginDatabase.GetPreparedStatement(LoginStatements.SEL_AUTOBROADCAST); - stmt.AddValue(0, _realm.Id.Index); + stmt.AddValue(0, Global.RealmMgr.GetCurrentRealmId().Index); SQLResult result = DB.Login.Query(stmt); if (result.IsEmpty()) @@ -1442,7 +1440,7 @@ namespace Game stmt.AddValue(0, tmpDiff); stmt.AddValue(1, maxOnlinePlayers); - stmt.AddValue(2, _realm.Id.Index); + stmt.AddValue(2, Global.RealmMgr.GetCurrentRealmId().Index); stmt.AddValue(3, (uint)GameTime.GetStartTime()); DB.Login.Execute(stmt); @@ -1458,7 +1456,7 @@ namespace Game PreparedStatement stmt = LoginDatabase.GetPreparedStatement(LoginStatements.DEL_OLD_LOGS); stmt.AddValue(0, WorldConfig.GetIntValue(WorldCfg.LogdbCleartime)); stmt.AddValue(1, 0); - stmt.AddValue(2, GetRealm().Id.Index); + stmt.AddValue(2, Global.RealmMgr.GetCurrentRealmId().Index); DB.Login.Execute(stmt); } @@ -2021,7 +2019,7 @@ namespace Game PreparedStatement stmt = LoginDatabase.GetPreparedStatement(LoginStatements.REP_REALM_CHARACTERS); stmt.AddValue(0, charCount); stmt.AddValue(1, Id); - stmt.AddValue(2, _realm.Id.Index); + stmt.AddValue(2, Global.RealmMgr.GetCurrentRealmId().Index); DB.Login.DirectExecute(stmt); } } @@ -2454,30 +2452,6 @@ namespace Game public Locale GetDefaultDbcLocale() { return m_defaultDbcLocale; } - public bool LoadRealmInfo() - { - SQLResult result = DB.Login.Query("SELECT id, name, address, localAddress, port, icon, flag, timezone, allowedSecurityLevel, population, gamebuild, Region, Battlegroup FROM realmlist WHERE id = {0}", _realm.Id.Index); - if (result.IsEmpty()) - return false; - - _realm.SetName(result.Read(1)); - _realm.Addresses.Add(System.Net.IPAddress.Parse(result.Read(2))); - _realm.Addresses.Add(System.Net.IPAddress.Parse(result.Read(3))); - _realm.Port = result.Read(4); - _realm.Type = result.Read(5); - _realm.Flags = (RealmFlags)result.Read(6); - _realm.Timezone = result.Read(7); - _realm.AllowedSecurityLevel = (AccountTypes)result.Read(8); - _realm.PopulationLevel = result.Read(9); - _realm.Build = result.Read(10); - _realm.Id.Region = result.Read(11); - _realm.Id.Site = result.Read(12); - return true; - } - - public Realm GetRealm() { return _realm; } - public RealmId GetRealmId() { return _realm.Id; } - public void RemoveOldCorpses() { m_timers[WorldTimers.Corpses].SetCurrent(m_timers[WorldTimers.Corpses].GetInterval()); @@ -2545,7 +2519,7 @@ namespace Game public uint GetVirtualRealmAddress() { - return _realm.Id.GetAddress(); + return Global.RealmMgr.GetCurrentRealmId().GetAddress(); } public float GetMaxVisibleDistanceOnContinents() { return m_MaxVisibleDistanceOnContinents; } @@ -2632,8 +2606,6 @@ namespace Game AsyncCallbackProcessor _queryProcessor = new(); - Realm _realm; - string _dataPath; string m_DBVersion; diff --git a/Source/Scripts/World/ActionIpLogger.cs b/Source/Scripts/World/ActionIpLogger.cs index 285cbf185..fbb7759fe 100644 --- a/Source/Scripts/World/ActionIpLogger.cs +++ b/Source/Scripts/World/ActionIpLogger.cs @@ -86,7 +86,7 @@ namespace Scripts.World.Achievements // We declare all the required variables uint playerGuid = accountId; - uint realmId = Global.WorldMgr.GetRealmId().Index; + uint realmId = Global.RealmMgr.GetCurrentRealmId().Index; string systemNote = "Error"; // "Error" is a placeholder here. We change it later. // With this switch, we change systemNote so that we have a more accurate phraMath.Sing of what type it is. @@ -193,7 +193,7 @@ namespace Scripts.World.Achievements // We declare all the required variables uint playerGuid = player.GetSession().GetAccountId(); - uint realmId = Global.WorldMgr.GetRealmId().Index; + uint realmId = Global.RealmMgr.GetCurrentRealmId().Index; string currentIp = player.GetSession().GetRemoteAddress(); string systemNote; @@ -261,7 +261,7 @@ namespace Scripts.World.Achievements // Action Ip Logger is only intialized if config is set up // Else, this script isn't loaded in the first place: We require no config check. - uint realmId = Global.WorldMgr.GetRealmId().Index; + uint realmId = Global.RealmMgr.GetCurrentRealmId().Index; // Query playerGuid/accountId, as we only have characterGuid string systemNote; diff --git a/Source/WorldServer/Server.cs b/Source/WorldServer/Server.cs index f52e2001f..8ee9388e1 100644 --- a/Source/WorldServer/Server.cs +++ b/Source/WorldServer/Server.cs @@ -36,11 +36,30 @@ namespace WorldServer // Server startup begin uint startupBegin = Time.GetMSTime(); - // set server offline (not connectable) - DB.Login.DirectExecute("UPDATE realmlist SET flag = (flag & ~{0}) | {1} WHERE id = '{2}'", (uint)RealmFlags.VersionMismatch, (uint)RealmFlags.Offline, Global.WorldMgr.GetRealm().Id.Index); - Global.RealmMgr.Initialize(ConfigMgr.GetDefaultValue("RealmsStateUpdateDelay", 10)); + ///- Get the realm Id from the configuration file + uint realmId = ConfigMgr.GetDefaultValue("RealmID", 0u); + if (realmId == 0) + { + Log.outError(LogFilter.ServerLoading, "Realm ID not defined in configuration file"); + ExitNow(); + } + + Global.RealmMgr.SetCurrentRealmId(new Framework.Realm.RealmId(realmId)); + + Log.outInfo(LogFilter.ServerLoading, $"Realm running as realm ID {realmId}"); + + ///- Clean the database before starting + ClearOnlineAccounts(realmId); + + var realm = Global.RealmMgr.GetCurrentRealm(); + if (realm == null) + ExitNow(); + + // Set server offline (not connectable) + DB.Login.DirectExecute($"UPDATE realmlist SET flag = flag | {LegacyRealmFlags.Offline} WHERE id = '{realmId}'"); + if (!Global.WorldMgr.SetInitialWorldSettings()) ExitNow(); @@ -75,9 +94,7 @@ namespace WorldServer } // set server online (allow connecting now) - DB.Login.DirectExecute("UPDATE realmlist SET flag = flag & ~{0}, population = 0 WHERE id = '{1}'", (uint)RealmFlags.Offline, Global.WorldMgr.GetRealm().Id.Index); - Global.WorldMgr.GetRealm().PopulationLevel = 0.0f; - Global.WorldMgr.GetRealm().Flags = Global.WorldMgr.GetRealm().Flags & ~RealmFlags.VersionMismatch; + DB.Login.DirectExecute($"UPDATE realmlist SET flag = flag & ~{LegacyRealmFlags.Offline}, population = 0 WHERE id = '{realmId}'"); GC.Collect(); GC.WaitForPendingFinalizers(); @@ -112,10 +129,10 @@ namespace WorldServer Global.ScriptMgr.Unload(); // set server offline - DB.Login.DirectExecute("UPDATE realmlist SET flag = flag | {0} WHERE id = '{1}'", (uint)RealmFlags.Offline, Global.WorldMgr.GetRealm().Id.Index); + DB.Login.DirectExecute($"UPDATE realmlist SET flag = flag | {LegacyRealmFlags.Offline} WHERE id = '{realmId}'"); Global.RealmMgr.Close(); - ClearOnlineAccounts(); + ClearOnlineAccounts(realmId); ExitNow(); } @@ -138,28 +155,16 @@ namespace WorldServer if (!loader.Load()) return false; - // Get the realm Id from the configuration file - Global.WorldMgr.GetRealm().Id.Index = ConfigMgr.GetDefaultValue("RealmID", 0u); - if (Global.WorldMgr.GetRealm().Id.Index == 0) - { - Log.outError(LogFilter.Server, "Realm ID not defined in configuration file"); - return false; - } - Log.outInfo(LogFilter.ServerLoading, "Realm running as realm ID {0} ", Global.WorldMgr.GetRealm().Id.Index); - - // Clean the database before starting - ClearOnlineAccounts(); - Global.WorldMgr.LoadDBVersion(); Log.outInfo(LogFilter.Server, $"Using World DB: {Global.WorldMgr.GetDBVersion()}"); return true; } - static void ClearOnlineAccounts() + static void ClearOnlineAccounts(uint realmId) { // Reset online status for all accounts with characters on the current realm - DB.Login.DirectExecute("UPDATE account SET online = 0 WHERE online > 0 AND id IN (SELECT acctid FROM realmcharacters WHERE realmid = {0})", Global.WorldMgr.GetRealm().Id.Index); + DB.Login.DirectExecute($"UPDATE account SET online = 0 WHERE online > 0 AND id IN (SELECT acctid FROM realmcharacters WHERE realmid = {realmId})"); // Reset online status for all characters DB.Characters.DirectExecute("UPDATE characters SET online = 0 WHERE online <> 0");