From 3634bc7133872aab674adc826232504a8e7eaaff Mon Sep 17 00:00:00 2001 From: hondacrx Date: Fri, 16 Aug 2019 13:43:17 -0400 Subject: [PATCH] Core/Misc: Moved CharacterInfo out of world to separate class Port From (https://github.com/TrinityCore/TrinityCore/commit/ad4e63bae145ae49b584ab2fc621660430cec0d3) --- Source/Framework/Constants/PlayerConst.cs | 7 + Source/Framework/Database/DatabaseUpdater.cs | 4 +- .../Database/Databases/CharacterDatabase.cs | 10 - Source/Game/Achievements/CriteriaHandler.cs | 6 +- Source/Game/Arenas/ArenaTeam.cs | 20 +- Source/Game/AuctionHouse/AuctionManager.cs | 20 +- Source/Game/BlackMarket/BlackMarketEntry.cs | 2 +- Source/Game/BlackMarket/BlackMarketManager.cs | 6 +- Source/Game/Cache/CharacterCache.cs | 249 ++++++++++++++++++ Source/Game/Calendar/CalendarManager.cs | 8 +- Source/Game/Chat/Channels/ChannelAppenders.cs | 7 +- Source/Game/Chat/CommandHandler.cs | 8 +- Source/Game/Chat/Commands/ArenaCommands.cs | 8 +- Source/Game/Chat/Commands/BanCommands.cs | 2 +- .../Game/Chat/Commands/CharacterCommands.cs | 23 +- Source/Game/Chat/Commands/GroupCommands.cs | 2 +- Source/Game/Chat/Commands/GuildCommands.cs | 6 +- Source/Game/Chat/Commands/LFGCommands.cs | 2 +- Source/Game/Chat/Commands/ListCommands.cs | 2 +- Source/Game/Chat/Commands/MiscCommands.cs | 8 +- Source/Game/Chat/Commands/TicketCommands.cs | 6 +- Source/Game/Entities/Corpse.cs | 2 +- Source/Game/Entities/Creature/Creature.cs | 2 +- Source/Game/Entities/GameObject/GameObject.cs | 5 +- Source/Game/Entities/Player/Player.DB.cs | 60 ++--- Source/Game/Entities/Player/Player.PvP.cs | 26 +- Source/Game/Entities/Player/Player.Quest.cs | 25 +- Source/Game/Entities/Player/Player.Talents.cs | 10 +- Source/Game/Entities/Player/Player.cs | 4 +- Source/Game/Entities/Unit/Unit.Spells.cs | 5 +- Source/Game/Entities/Unit/Unit.cs | 3 +- Source/Game/Events/GameEventManager.cs | 14 +- Source/Game/Globals/Global.cs | 2 + Source/Game/Globals/ObjectAccessor.cs | 6 +- Source/Game/Globals/ObjectManager.cs | 68 ----- Source/Game/Groups/Group.cs | 4 +- Source/Game/Guilds/Guild.cs | 13 +- Source/Game/Handlers/AuctionHandler.cs | 2 +- Source/Game/Handlers/CalendarHandler.cs | 17 +- Source/Game/Handlers/CharacterHandler.cs | 65 +++-- Source/Game/Handlers/GuildFinderHandler.cs | 7 +- Source/Game/Handlers/LFGHandler.cs | 4 +- Source/Game/Handlers/MailHandler.cs | 35 +-- Source/Game/Handlers/NPCHandler.cs | 6 - Source/Game/Handlers/PetitionsHandler.cs | 4 +- Source/Game/Handlers/SocialHandler.cs | 69 ++--- Source/Game/Handlers/SpellHandler.cs | 69 +++-- Source/Game/Mails/MailDraft.cs | 2 +- Source/Game/Maps/Map.cs | 12 +- Source/Game/Network/Packets/QueryPackets.cs | 9 +- Source/Game/Quest/Quest.cs | 4 + Source/Game/Scripting/CoreScripts.cs | 5 +- Source/Game/Scripting/ScriptManager.cs | 8 +- Source/Game/Server/WorldManager.cs | 121 +-------- Source/Game/Server/WorldSession.cs | 22 +- Source/Game/SupportSystem/SupportTickets.cs | 9 +- 56 files changed, 598 insertions(+), 527 deletions(-) create mode 100644 Source/Game/Cache/CharacterCache.cs diff --git a/Source/Framework/Constants/PlayerConst.cs b/Source/Framework/Constants/PlayerConst.cs index ed974b1bc..3bfb49b97 100644 --- a/Source/Framework/Constants/PlayerConst.cs +++ b/Source/Framework/Constants/PlayerConst.cs @@ -732,4 +732,11 @@ namespace Framework.Constants FailedCantDoThatChallengeModeActive = 7, FailedRestArea = 8 } + + public enum TutorialsFlag + { + None = 0x00, + Changed = 0x01, + LoadedFromDB = 0x02 + } } diff --git a/Source/Framework/Database/DatabaseUpdater.cs b/Source/Framework/Database/DatabaseUpdater.cs index 8d6c22579..95f0d905f 100644 --- a/Source/Framework/Database/DatabaseUpdater.cs +++ b/Source/Framework/Database/DatabaseUpdater.cs @@ -51,10 +51,10 @@ namespace Framework.Database fileName = @"/sql/base/characters_database.sql"; break; case "WorldDatabase": - fileName = @"/sql/TDB_world_735.00_2018_02_19.sql"; + fileName = @"/sql/TDB_full_world_820.19071_2019_07_15.sql"; break; case "HotfixDatabase": - fileName = @"/sql/TDB_hotfixes_735.00_2018_02_19.sql"; + fileName = @"/sql/TDB_full_hotfixes_820.19071_2019_07_15.sql"; break; } diff --git a/Source/Framework/Database/Databases/CharacterDatabase.cs b/Source/Framework/Database/Databases/CharacterDatabase.cs index 6e8e85271..589f911ec 100644 --- a/Source/Framework/Database/Databases/CharacterDatabase.cs +++ b/Source/Framework/Database/Databases/CharacterDatabase.cs @@ -32,7 +32,6 @@ namespace Framework.Database PrepareStatement(CharStatements.INS_QUEST_POOL_SAVE, "INSERT INTO pool_quest_save (pool_id, quest_id) VALUES (?, ?)"); PrepareStatement(CharStatements.DEL_NONEXISTENT_GUILD_BANK_ITEM, "DELETE FROM guild_bank_item WHERE guildid = ? AND TabId = ? AND SlotId = ?"); PrepareStatement(CharStatements.DEL_EXPIRED_BANS, "UPDATE character_banned SET active = 0 WHERE unbandate <= UNIX_TIMESTAMP() AND unbandate <> bandate"); - PrepareStatement(CharStatements.SEL_GUID_BY_NAME, "SELECT guid FROM characters WHERE name = ?"); PrepareStatement(CharStatements.SEL_CHECK_NAME, "SELECT 1 FROM characters WHERE name = ?"); PrepareStatement(CharStatements.SEL_CHECK_GUID, "SELECT 1 FROM characters WHERE guid = ?"); PrepareStatement(CharStatements.SEL_SUM_CHARS, "SELECT COUNT(guid) FROM characters WHERE account = ?"); @@ -67,8 +66,6 @@ namespace Framework.Database "LEFT JOIN character_declinedname AS cd ON c.guid = cd.guid LEFT JOIN guild_member AS gm ON c.guid = gm.guid " + "LEFT JOIN character_banned AS cb ON c.guid = cb.guid AND cb.active = 1 WHERE c.deleteInfos_Account = ? AND c.deleteInfos_Name IS NOT NULL"); PrepareStatement(CharStatements.SEL_FREE_NAME, "SELECT name, at_login FROM characters WHERE guid = ? AND NOT EXISTS (SELECT NULL FROM characters WHERE name = ?)"); - PrepareStatement(CharStatements.SEL_GUID_RACE_ACC_BY_NAME, "SELECT guid, race, account FROM characters WHERE name = ?"); - PrepareStatement(CharStatements.SEL_CHAR_LEVEL, "SELECT level FROM characters WHERE guid = ?"); PrepareStatement(CharStatements.SEL_CHAR_ZONE, "SELECT zone FROM characters WHERE guid = ?"); PrepareStatement(CharStatements.SEL_CHAR_POSITION_XYZ, "SELECT map, position_x, position_y, position_z FROM characters WHERE guid = ?"); PrepareStatement(CharStatements.SEL_CHAR_POSITION, "SELECT position_x, position_y, position_z, orientation, map, taxi_path FROM characters WHERE guid = ?"); @@ -358,7 +355,6 @@ namespace Framework.Database PrepareStatement(CharStatements.UPD_ARENA_TEAM_MEMBER, "UPDATE arena_team_member SET personalRating = ?, weekGames = ?, weekWins = ?, seasonGames = ?, seasonWins = ? WHERE arenaTeamId = ? AND guid = ?"); PrepareStatement(CharStatements.DEL_CHARACTER_ARENA_STATS, "DELETE FROM character_arena_stats WHERE guid = ?"); PrepareStatement(CharStatements.REP_CHARACTER_ARENA_STATS, "REPLACE INTO character_arena_stats (guid, slot, matchMakerRating) VALUES (?, ?, ?)"); - PrepareStatement(CharStatements.SEL_PLAYER_ARENA_TEAMS, "SELECT arena_team_member.arenaTeamId FROM arena_team_member JOIN arena_team ON arena_team_member.arenaTeamId = arena_team.arenaTeamId WHERE guid = ?"); PrepareStatement(CharStatements.UPD_ARENA_TEAM_NAME, "UPDATE arena_team SET name = ? WHERE arenaTeamId = ?"); // Character battleground data @@ -501,7 +497,6 @@ namespace Framework.Database PrepareStatement(CharStatements.SEL_CHAR_COD_ITEM_MAIL, "SELECT id, messageType, mailTemplateId, sender, subject, body, money, has_items FROM mail WHERE receiver = ? AND has_items <> 0 AND cod <> 0"); PrepareStatement(CharStatements.SEL_CHAR_SOCIAL, "SELECT DISTINCT guid FROM character_social WHERE friend = ?"); PrepareStatement(CharStatements.SEL_CHAR_OLD_CHARS, "SELECT guid, deleteInfos_Account FROM characters WHERE deleteDate IS NOT NULL AND deleteDate < ?"); - PrepareStatement(CharStatements.SEL_ARENA_TEAM_ID_BY_PLAYER_GUID, "SELECT arena_team_member.arenateamid FROM arena_team_member JOIN arena_team ON arena_team_member.arenateamid = arena_team.arenateamid WHERE guid = ? AND type = ? LIMIT 1"); PrepareStatement(CharStatements.SEL_MAIL, "SELECT id, messageType, sender, receiver, subject, body, has_items, expire_time, deliver_time, money, cod, checked, stationery, mailTemplateId FROM mail WHERE receiver = ? ORDER BY id DESC"); PrepareStatement(CharStatements.DEL_CHAR_AURA_FROZEN, "DELETE FROM character_aura WHERE spell = 9454 AND guid = ?"); PrepareStatement(CharStatements.SEL_CHAR_INVENTORY_COUNT_ITEM, "SELECT COUNT(itemEntry) FROM character_inventory ci INNER JOIN item_instance ii ON ii.guid = ci.item WHERE itemEntry = ?"); @@ -752,7 +747,6 @@ namespace Framework.Database INS_QUEST_POOL_SAVE, DEL_NONEXISTENT_GUILD_BANK_ITEM, DEL_EXPIRED_BANS, - SEL_GUID_BY_NAME, SEL_CHECK_NAME, SEL_CHECK_GUID, SEL_SUM_CHARS, @@ -772,8 +766,6 @@ namespace Framework.Database SEL_UNDELETE_ENUM, SEL_UNDELETE_ENUM_DECLINED_NAME, SEL_FREE_NAME, - SEL_GUID_RACE_ACC_BY_NAME, - SEL_CHAR_LEVEL, SEL_CHAR_ZONE, SEL_CHAR_POSITION_XYZ, SEL_CHAR_POSITION, @@ -1000,7 +992,6 @@ namespace Framework.Database UPD_ARENA_TEAM_MEMBER, DEL_CHARACTER_ARENA_STATS, REP_CHARACTER_ARENA_STATS, - SEL_PLAYER_ARENA_TEAMS, UPD_ARENA_TEAM_NAME, SEL_PETITION, @@ -1133,7 +1124,6 @@ namespace Framework.Database SEL_CHAR_COD_ITEM_MAIL, SEL_CHAR_SOCIAL, SEL_CHAR_OLD_CHARS, - SEL_ARENA_TEAM_ID_BY_PLAYER_GUID, SEL_MAIL, DEL_CHAR_AURA_FROZEN, SEL_CHAR_INVENTORY_COUNT_ITEM, diff --git a/Source/Game/Achievements/CriteriaHandler.cs b/Source/Game/Achievements/CriteriaHandler.cs index 2f130ed70..3fe1494bf 100644 --- a/Source/Game/Achievements/CriteriaHandler.cs +++ b/Source/Game/Achievements/CriteriaHandler.cs @@ -268,7 +268,11 @@ namespace Game.Achievements foreach (var skill in bounds) { if (skill.SkillLine == criteria.Entry.Asset) - spellCount++; + { + // do not add couter twice if by any chance skill is listed twice in dbc (eg. skill 777 and spell 22717) + ++spellCount; + break; + } } } SetCriteriaProgress(criteria, spellCount, referencePlayer); diff --git a/Source/Game/Arenas/ArenaTeam.cs b/Source/Game/Arenas/ArenaTeam.cs index 48874527f..8f38e1e4b 100644 --- a/Source/Game/Arenas/ArenaTeam.cs +++ b/Source/Game/Arenas/ArenaTeam.cs @@ -23,6 +23,7 @@ using Game.Network; using System; using System.Collections.Generic; using System.Linq; +using Game.Cache; namespace Game.Arenas { @@ -87,24 +88,24 @@ namespace Game.Arenas if (GetMembersSize() >= GetArenaType() * 2) return false; - // Get player name and class either from db or ObjectMgr - CharacterInfo characterInfo; + // Get player name and class either from db or character cache + CharacterCacheEntry characterInfo; Player player = Global.ObjAccessor.FindPlayer(playerGuid); if (player) { playerClass = player.GetClass(); playerName = player.GetName(); } - else if ((characterInfo = Global.WorldMgr.GetCharacterInfo(playerGuid)) != null) + else if ((characterInfo = Global.CharacterCacheStorage.GetCharacterCacheByGuid(playerGuid)) != null) { playerName = characterInfo.Name; - playerClass = characterInfo.ClassID; + playerClass = characterInfo.ClassId; } else return false; // Check if player is already in a similar arena team - if ((player && player.GetArenaTeamId(GetSlot()) != 0) || Player.GetArenaTeamIdFromDB(playerGuid, GetArenaType()) != 0) + if ((player && player.GetArenaTeamId(GetSlot()) != 0) || Global.CharacterCacheStorage.GetCharacterArenaTeamIdByGuid(playerGuid, GetArenaType()) != 0) { Log.outDebug(LogFilter.Arena, "Arena: {0} {1} already has an arena team of type {2}", playerGuid.ToString(), playerName, GetArenaType()); return false; @@ -147,6 +148,7 @@ namespace Game.Arenas newMember.MatchMakerRating = (ushort)matchMakerRating; Members.Add(newMember); + Global.CharacterCacheStorage.UpdateCharacterArenaTeamId(playerGuid, GetSlot(), GetId()); // Save player's arena team membership to db stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_ARENA_TEAM_MEMBER); @@ -234,6 +236,7 @@ namespace Game.Arenas // Put the player in the team Members.Add(newMember); + Global.CharacterCacheStorage.UpdateCharacterArenaTeamId(newMember.Guid, GetSlot(), GetId()); } while (result.NextRow()); @@ -294,11 +297,14 @@ namespace Game.Arenas { // Remove member from team foreach (var member in Members) + { if (member.Guid == guid) { Members.Remove(member); + Global.CharacterCacheStorage.UpdateCharacterArenaTeamId(guid, GetSlot(), 0); break; } + } // Remove arena team info from player data Player player = Global.ObjAccessor.FindPlayer(guid); @@ -347,7 +353,7 @@ namespace Game.Arenas DB.Characters.CommitTransaction(trans); - // Remove arena team from ObjectMgr + // Remove arena team from ArenaTeamMgr Global.ArenaTeamMgr.RemoveArenaTeam(teamId); } @@ -370,7 +376,7 @@ namespace Game.Arenas DB.Characters.CommitTransaction(trans); - // Remove arena team from ObjectMgr + // Remove arena team from ArenaTeamMgr Global.ArenaTeamMgr.RemoveArenaTeam(teamId); } diff --git a/Source/Game/AuctionHouse/AuctionManager.cs b/Source/Game/AuctionHouse/AuctionManager.cs index c8c2591be..071339893 100644 --- a/Source/Game/AuctionHouse/AuctionManager.cs +++ b/Source/Game/AuctionHouse/AuctionManager.cs @@ -93,10 +93,10 @@ namespace Game } else { - bidderAccId = ObjectManager.GetPlayerAccountIdByGUID(bidderGuid); + bidderAccId = Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(bidderGuid); logGmTrade = Global.AccountMgr.HasPermission(bidderAccId, RBACPermissions.LogGmTrade, Global.WorldMgr.GetRealm().Id.Realm); - if (logGmTrade && !ObjectManager.GetPlayerNameByGUID(bidderGuid, out bidderName)) + if (logGmTrade && !Global.CharacterCacheStorage.GetCharacterNameByGuid(bidderGuid, out bidderName)) bidderName = Global.ObjectMgr.GetCypherString(CypherStrings.Unknown); } @@ -104,10 +104,10 @@ namespace Game { ObjectGuid ownerGuid = ObjectGuid.Create(HighGuid.Player, auction.owner); string ownerName; - if (!ObjectManager.GetPlayerNameByGUID(ownerGuid, out ownerName)) + if (!Global.CharacterCacheStorage.GetCharacterNameByGuid(ownerGuid, out ownerName)) ownerName = Global.ObjectMgr.GetCypherString(CypherStrings.Unknown); - uint ownerAccId = ObjectManager.GetPlayerAccountIdByGUID(ownerGuid); + uint ownerAccId = Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(ownerGuid); Log.outCommand(bidderAccId, $"GM {bidderName} (Account: {bidderAccId}) won item in auction: {item.GetTemplate().GetName()} (Entry: {item.GetEntry()} Count: {item.GetCount()}) and pay money: {auction.bid}. Original owner {ownerName} (Account: {ownerAccId})"); } @@ -144,7 +144,7 @@ namespace Game { ObjectGuid owner_guid = ObjectGuid.Create(HighGuid.Player, auction.owner); Player owner = Global.ObjAccessor.FindPlayer(owner_guid); - uint owner_accId = ObjectManager.GetPlayerAccountIdByGUID(owner_guid); + uint owner_accId = Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(owner_guid); // owner exist (online or offline) if (owner || owner_accId != 0) new MailDraft(auction.BuildAuctionMailSubject(MailAuctionAnswers.SalePending), AuctionEntry.BuildAuctionMailBody(auction.bidder, auction.bid, auction.buyout, auction.deposit, auction.GetAuctionCut())) @@ -156,7 +156,7 @@ namespace Game { ObjectGuid owner_guid = ObjectGuid.Create(HighGuid.Player, auction.owner); Player owner = Global.ObjAccessor.FindPlayer(owner_guid); - uint owner_accId = ObjectManager.GetPlayerAccountIdByGUID(owner_guid); + uint owner_accId = Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(owner_guid); Item item = GetAItem(auction.itemGUIDLow); // owner exist @@ -189,7 +189,7 @@ namespace Game ObjectGuid owner_guid = ObjectGuid.Create(HighGuid.Player, auction.owner); Player owner = Global.ObjAccessor.FindPlayer(owner_guid); - uint owner_accId = ObjectManager.GetPlayerAccountIdByGUID(owner_guid); + uint owner_accId = Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(owner_guid); // owner exist if (owner || owner_accId != 0) { @@ -215,7 +215,7 @@ namespace Game uint oldBidder_accId = 0; if (oldBidder == null) - oldBidder_accId = ObjectManager.GetPlayerAccountIdByGUID(oldBidder_guid); + oldBidder_accId = Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(oldBidder_guid); Item item = GetAItem(auction.itemGUIDLow); @@ -239,7 +239,7 @@ namespace Game uint bidder_accId = 0; if (!bidder) - bidder_accId = ObjectManager.GetPlayerAccountIdByGUID(bidder_guid); + bidder_accId = Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(bidder_guid); // bidder exist if (bidder || bidder_accId != 0) @@ -599,7 +599,7 @@ namespace Game auctionItem.ItemGuid = item.GetGUID(); auctionItem.MinBid = startbid; auctionItem.Owner = ObjectGuid.Create(HighGuid.Player, owner); - auctionItem.OwnerAccountID = ObjectGuid.Create(HighGuid.WowAccount, ObjectManager.GetPlayerAccountIdByGUID(auctionItem.Owner)); + auctionItem.OwnerAccountID = ObjectGuid.Create(HighGuid.WowAccount, Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(auctionItem.Owner)); auctionItem.MinIncrement = bidder != 0 ? GetAuctionOutBid() : 0; auctionItem.Bidder = bidder != 0 ? ObjectGuid.Create(HighGuid.Player, bidder) : ObjectGuid.Empty; auctionItem.BidAmount = bidder != 0 ? bid : 0; diff --git a/Source/Game/BlackMarket/BlackMarketEntry.cs b/Source/Game/BlackMarket/BlackMarketEntry.cs index 5dbc4c14b..194135ce3 100644 --- a/Source/Game/BlackMarket/BlackMarketEntry.cs +++ b/Source/Game/BlackMarket/BlackMarketEntry.cs @@ -128,7 +128,7 @@ namespace Game.BlackMarket _bidder = fields.Read(4); // Either no bidder or existing player - if (_bidder != 0 && ObjectManager.GetPlayerAccountIdByGUID(ObjectGuid.Create(HighGuid.Player, _bidder)) == 0) // Probably a better way to check if player exists + if (_bidder != 0 && Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(ObjectGuid.Create(HighGuid.Player, _bidder)) == 0) // Probably a better way to check if player exists { Log.outError(LogFilter.Misc, "Black market auction {0} does not have a valid bidder (GUID: {1}).", _marketId, _bidder); return false; diff --git a/Source/Game/BlackMarket/BlackMarketManager.cs b/Source/Game/BlackMarket/BlackMarketManager.cs index 8bd9bb7c5..65feba6a9 100644 --- a/Source/Game/BlackMarket/BlackMarketManager.cs +++ b/Source/Game/BlackMarket/BlackMarketManager.cs @@ -229,13 +229,13 @@ namespace Game.BlackMarket } else { - bidderAccId = ObjectManager.GetPlayerAccountIdByGUID(bidderGuid); + bidderAccId = Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(bidderGuid); if (bidderAccId == 0) // Account exists return; logGmTrade = Global.AccountMgr.HasPermission(bidderAccId, RBACPermissions.LogGmTrade, Global.WorldMgr.GetRealmId().Realm); - if (logGmTrade && !ObjectManager.GetPlayerNameByGUID(bidderGuid, out bidderName)) + if (logGmTrade && !Global.CharacterCacheStorage.GetCharacterNameByGuid(bidderGuid, out bidderName)) bidderName = Global.ObjectMgr.GetCypherString(CypherStrings.Unknown); } @@ -277,7 +277,7 @@ namespace Game.BlackMarket uint oldBidder_accId = 0; if (!oldBidder) - oldBidder_accId = ObjectManager.GetPlayerAccountIdByGUID(oldBidder_guid); + oldBidder_accId = Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(oldBidder_guid); // old bidder exist if (!oldBidder && oldBidder_accId == 0) diff --git a/Source/Game/Cache/CharacterCache.cs b/Source/Game/Cache/CharacterCache.cs new file mode 100644 index 000000000..8a37be50d --- /dev/null +++ b/Source/Game/Cache/CharacterCache.cs @@ -0,0 +1,249 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Game.Entities; +using Framework.Database; +using Framework.Constants; +using Game.Arenas; +using Game.Network.Packets; + +namespace Game.Cache +{ + public class CharacterCache : Singleton + { + Dictionary _characterCacheStore = new Dictionary(); + Dictionary _characterCacheByNameStore = new Dictionary(); + + CharacterCache() { } + + public void LoadCharacterCacheStorage() + { + _characterCacheStore.Clear(); + uint oldMSTime = Time.GetMSTime(); + + SQLResult result = DB.Characters.Query("SELECT guid, name, account, race, gender, class, level, deleteDate FROM characters"); + if (result.IsEmpty()) + { + Log.outInfo(LogFilter.ServerLoading, "No character name data loaded, empty query"); + return; + } + + do + { + AddCharacterCacheEntry(ObjectGuid.Create(HighGuid.Player, result.Read(0)), result.Read(2), result.Read(1), result.Read(4), result.Read(3), result.Read(5), result.Read(6), result.Read(7) != 0); + } while (result.NextRow()); + + Log.outInfo(LogFilter.ServerLoading, $"Loaded character infos for {_characterCacheStore.Count} characters in {Time.GetMSTimeDiffToNow(oldMSTime)} ms"); + } + + public void AddCharacterCacheEntry(ObjectGuid guid, uint accountId, string name, byte gender, byte race, byte playerClass, byte level, bool isDeleted) + { + var data = new CharacterCacheEntry(); + data.Guid = guid; + data.Name = name; + data.AccountId = accountId; + data.RaceId = (Race)race; + data.Sex = (Gender)gender; + data.ClassId = (Class)playerClass; + data.Level = level; + data.GuildId = 0; // Will be set in guild loading or guild setting + for (byte i = 0; i < SharedConst.MaxArenaSlot; ++i) + data.ArenaTeamId[i] = 0; // Will be set in arena teams loading + data.IsDeleted = isDeleted; + + // Fill Name to Guid Store + _characterCacheByNameStore[name] = data; + _characterCacheStore[guid] = data; + } + + public void DeleteCharacterCacheEntry(ObjectGuid guid, string name) + { + _characterCacheStore.Remove(guid); + _characterCacheByNameStore.Remove(name); + } + + public void UpdateCharacterData(ObjectGuid guid, string name, byte? gender = null, byte? race = null) + { + var characterCacheEntry = _characterCacheStore.LookupByKey(guid); + if (characterCacheEntry == null) + return; + + string oldName = characterCacheEntry.Name; + characterCacheEntry.Name = name; + + if (gender.HasValue) + characterCacheEntry.Sex = (Gender)gender.Value; + + if (race.HasValue) + characterCacheEntry.RaceId = (Race)race.Value; + + InvalidatePlayer invalidatePlayer = new InvalidatePlayer(); + invalidatePlayer.Guid = guid; + Global.WorldMgr.SendGlobalMessage(invalidatePlayer); + + // Correct name -> pointer storage + _characterCacheByNameStore.Remove(oldName); + _characterCacheByNameStore[name] = characterCacheEntry; + } + + public void UpdateCharacterLevel(ObjectGuid guid, byte level) + { + if (!_characterCacheStore.ContainsKey(guid)) + return; + + _characterCacheStore[guid].Level = level; + } + + public void UpdateCharacterAccountId(ObjectGuid guid, uint accountId) + { + if (!_characterCacheStore.ContainsKey(guid)) + return; + + _characterCacheStore[guid].AccountId = accountId; + } + + public void UpdateCharacterGuildId(ObjectGuid guid, ulong guildId) + { + if (!_characterCacheStore.ContainsKey(guid)) + return; + + _characterCacheStore[guid].GuildId = guildId; + } + + public void UpdateCharacterArenaTeamId(ObjectGuid guid, byte slot, uint arenaTeamId) + { + if (!_characterCacheStore.ContainsKey(guid)) + return; + + _characterCacheStore[guid].ArenaTeamId[slot] = arenaTeamId; + } + + public void UpdateCharacterInfoDeleted(ObjectGuid guid, bool deleted, string name = null) + { + if (!_characterCacheStore.ContainsKey(guid)) + return; + + _characterCacheStore[guid].IsDeleted = deleted; + if (!name.IsEmpty()) + _characterCacheStore[guid].Name = name; + } + + public bool HasCharacterCacheEntry(ObjectGuid guid) + { + return _characterCacheStore.ContainsKey(guid); + } + + public CharacterCacheEntry GetCharacterCacheByGuid(ObjectGuid guid) + { + return _characterCacheStore.LookupByKey(guid); + } + + public CharacterCacheEntry GetCharacterCacheByName(string name) + { + return _characterCacheByNameStore.LookupByKey(name); + } + + public ObjectGuid GetCharacterGuidByName(string name) + { + var characterCacheEntry = _characterCacheByNameStore.LookupByKey(name); + if (characterCacheEntry != null) + return characterCacheEntry.Guid; + + return ObjectGuid.Empty; + } + + public bool GetCharacterNameByGuid(ObjectGuid guid, out string name) + { + name = "Unknown"; + var characterCacheEntry = _characterCacheStore.LookupByKey(guid); + if (characterCacheEntry == null) + return false; + + name = characterCacheEntry.Name; + return true; + } + + public Team GetCharacterTeamByGuid(ObjectGuid guid) + { + var characterCacheEntry = _characterCacheStore.LookupByKey(guid); + if (characterCacheEntry == null) + return 0; + + return Player.TeamForRace(characterCacheEntry.RaceId); + } + + public uint GetCharacterAccountIdByGuid(ObjectGuid guid) + { + var characterCacheEntry = _characterCacheStore.LookupByKey(guid); + if (characterCacheEntry == null) + return 0; + + return characterCacheEntry.AccountId; + } + + public uint GetCharacterAccountIdByName(string name) + { + var characterCacheEntry = _characterCacheByNameStore.LookupByKey(name); + if (characterCacheEntry != null) + return characterCacheEntry.AccountId; + + return 0; + } + + public byte GetCharacterLevelByGuid(ObjectGuid guid) + { + var characterCacheEntry = _characterCacheStore.LookupByKey(guid); + if (characterCacheEntry == null) + return 0; + + return characterCacheEntry.Level; + } + + public ulong GetCharacterGuildIdByGuid(ObjectGuid guid) + { + var characterCacheEntry = _characterCacheStore.LookupByKey(guid); + if (characterCacheEntry == null) + return 0; + + return characterCacheEntry.GuildId; + } + + public uint GetCharacterArenaTeamIdByGuid(ObjectGuid guid, byte type) + { + var characterCacheEntry = _characterCacheStore.LookupByKey(guid); + if (characterCacheEntry == null) + return 0; + + return characterCacheEntry.ArenaTeamId[ArenaTeam.GetSlotByType(type)]; + } + + public bool GetCharacterNameAndClassByGUID(ObjectGuid guid, out string name, out byte _class) + { + name = "Unknown"; + _class = 0; + + var characterCacheEntry = _characterCacheStore.LookupByKey(guid); + if (characterCacheEntry == null) + return false; + + name = characterCacheEntry.Name; + _class = (byte)characterCacheEntry.ClassId; + return true; + } + + } + + public class CharacterCacheEntry + { + public ObjectGuid Guid; + public string Name; + public uint AccountId; + public Class ClassId; + public Race RaceId; + public Gender Sex; + public byte Level; + public ulong GuildId; + public uint[] ArenaTeamId = new uint[SharedConst.MaxArenaSlot]; + public bool IsDeleted; + } +} diff --git a/Source/Game/Calendar/CalendarManager.cs b/Source/Game/Calendar/CalendarManager.cs index 7682315fe..80574623d 100644 --- a/Source/Game/Calendar/CalendarManager.cs +++ b/Source/Game/Calendar/CalendarManager.cs @@ -60,7 +60,7 @@ namespace Game ulong guildID = 0; if (flags.HasAnyFlag(CalendarFlags.GuildEvent) || flags.HasAnyFlag(CalendarFlags.WithoutInvites)) - guildID = Player.GetGuildIdFromDB(ownerGUID); + guildID = Global.CharacterCacheStorage.GetCharacterGuildIdByGuid(ownerGUID); CalendarEvent calendarEvent = new CalendarEvent(eventID, ownerGUID, guildID, type, textureID, date, flags, title, description, lockDate); _events.Add(calendarEvent); @@ -397,7 +397,7 @@ namespace Game ObjectGuid invitee = invite.InviteeGuid; Player player = Global.ObjAccessor.FindPlayer(invitee); - uint level = player ? player.getLevel() : Player.GetLevelFromDB(invitee); + uint level = player ? player.getLevel() : Global.CharacterCacheStorage.GetCharacterLevelByGuid(invitee); SCalendarEventInvite packet = new SCalendarEventInvite(); packet.EventID = calendarEvent != null ? calendarEvent.EventId : 0; @@ -545,8 +545,8 @@ namespace Game ObjectGuid inviteeGuid = calendarInvite.InviteeGuid; Player invitee = Global.ObjAccessor.FindPlayer(inviteeGuid); - uint inviteeLevel = invitee ? invitee.getLevel() : Player.GetLevelFromDB(inviteeGuid); - ulong inviteeGuildId = invitee ? invitee.GetGuildId() : Player.GetGuildIdFromDB(inviteeGuid); + uint inviteeLevel = invitee ? invitee.getLevel() : Global.CharacterCacheStorage.GetCharacterLevelByGuid(inviteeGuid); + ulong inviteeGuildId = invitee ? invitee.GetGuildId() : Global.CharacterCacheStorage.GetCharacterGuildIdByGuid(inviteeGuid); CalendarEventInviteInfo inviteInfo = new CalendarEventInviteInfo(); inviteInfo.Guid = inviteeGuid; diff --git a/Source/Game/Chat/Channels/ChannelAppenders.cs b/Source/Game/Chat/Channels/ChannelAppenders.cs index 40635c45c..b6dcaa615 100644 --- a/Source/Game/Chat/Channels/ChannelAppenders.cs +++ b/Source/Game/Chat/Channels/ChannelAppenders.cs @@ -19,6 +19,7 @@ using Framework.Constants; using Game.Entities; using Game.Network; using Game.Network.Packets; +using Game.Cache; namespace Game.Chat { @@ -399,9 +400,9 @@ namespace Game.Chat _ownerGuid = ownerGuid; _ownerName = ""; - CharacterInfo characterInfo = Global.WorldMgr.GetCharacterInfo(_ownerGuid); - if (characterInfo != null) - _ownerName = characterInfo.Name; + CharacterCacheEntry characterCacheEntry = Global.CharacterCacheStorage.GetCharacterCacheByGuid(_ownerGuid); + if (characterCacheEntry != null) + _ownerName = characterCacheEntry.Name; } public ChatNotify GetNotificationType() => ChatNotify.ChannelOwnerNotice; diff --git a/Source/Game/Chat/CommandHandler.cs b/Source/Game/Chat/CommandHandler.cs index 5d9de0cd0..0064127dd 100644 --- a/Source/Game/Chat/CommandHandler.cs +++ b/Source/Game/Chat/CommandHandler.cs @@ -405,7 +405,7 @@ namespace Game.Chat } player = Global.ObjAccessor.FindPlayerByName(name); - ObjectGuid guid = player == null ? ObjectManager.GetPlayerGUIDByName(name) : ObjectGuid.Empty; + ObjectGuid guid = player == null ? Global.CharacterCacheStorage.GetCharacterGuidByName(name) : ObjectGuid.Empty; playerGuid = player != null ? player.GetGUID() : guid; playerName = player != null || !guid.IsEmpty() ? name : ""; @@ -455,7 +455,7 @@ namespace Game.Chat if (player) return player.GetGUID().GetCounter(); - ObjectGuid guid = ObjectManager.GetPlayerGUIDByName(idS); + ObjectGuid guid = Global.CharacterCacheStorage.GetCharacterGuidByName(idS); if (guid.IsEmpty()) return 0; @@ -664,7 +664,7 @@ namespace Game.Chat if (target != null) target_session = target.GetSession(); else if (!guid.IsEmpty()) - target_account = ObjectManager.GetPlayerAccountIdByGUID(guid); + target_account = Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(guid); if (target_session == null && target_account == 0) { @@ -811,7 +811,7 @@ namespace Game.Chat player = Global.ObjAccessor.FindPlayerByName(name); if (offline) - guid = ObjectManager.GetPlayerGUIDByName(name); + guid = Global.CharacterCacheStorage.GetCharacterGuidByName(name); } if (player) diff --git a/Source/Game/Chat/Commands/ArenaCommands.cs b/Source/Game/Chat/Commands/ArenaCommands.cs index 40fd2df7d..37b82e5e1 100644 --- a/Source/Game/Chat/Commands/ArenaCommands.cs +++ b/Source/Game/Chat/Commands/ArenaCommands.cs @@ -51,7 +51,7 @@ namespace Game.Chat if (type == 2 || type == 3 || type == 5) { - if (Player.GetArenaTeamIdFromDB(target.GetGUID(), type) != 0) + if (Global.CharacterCacheStorage.GetCharacterArenaTeamIdByGuid(target.GetGUID(), type) != 0) { handler.SendSysMessage(CypherStrings.ArenaErrorSize, target.GetName()); return false; @@ -222,11 +222,11 @@ namespace Game.Chat arena.SetCaptain(targetGuid); - CharacterInfo oldCaptainNameData = Global.WorldMgr.GetCharacterInfo(arena.GetCaptain()); - if (oldCaptainNameData == null) + string oldCaptainName; + if (!Global.CharacterCacheStorage.GetCharacterNameByGuid(arena.GetCaptain(), out oldCaptainName)) return false; - handler.SendSysMessage(CypherStrings.ArenaCaptain, arena.GetName(), arena.GetId(), oldCaptainNameData.Name, target.GetName()); + handler.SendSysMessage(CypherStrings.ArenaCaptain, arena.GetName(), arena.GetId(), oldCaptainName, target.GetName()); if (handler.GetSession() != null) Log.outDebug(LogFilter.Arena, "GameMaster: {0} [GUID: {1}] promoted player: {2} [GUID: {3}] to leader of arena team \"{4}\"[Id: {5}]", handler.GetSession().GetPlayer().GetName(), handler.GetSession().GetPlayer().GetGUID().ToString(), target.GetName(), target.GetGUID().ToString(), arena.GetName(), arena.GetId()); diff --git a/Source/Game/Chat/Commands/BanCommands.cs b/Source/Game/Chat/Commands/BanCommands.cs index a3cb1ebcc..57562c51e 100644 --- a/Source/Game/Chat/Commands/BanCommands.cs +++ b/Source/Game/Chat/Commands/BanCommands.cs @@ -224,7 +224,7 @@ namespace Game.Chat.Commands if (!target) { - targetGuid = ObjectManager.GetPlayerGUIDByName(name); + targetGuid = Global.CharacterCacheStorage.GetCharacterGuidByName(name); if (targetGuid.IsEmpty()) { handler.SendSysMessage(CypherStrings.BaninfoNocharacter); diff --git a/Source/Game/Chat/Commands/CharacterCommands.cs b/Source/Game/Chat/Commands/CharacterCommands.cs index e17e06132..742277e3c 100644 --- a/Source/Game/Chat/Commands/CharacterCommands.cs +++ b/Source/Game/Chat/Commands/CharacterCommands.cs @@ -18,6 +18,7 @@ using Framework.Constants; using Framework.Database; using Framework.IO; +using Game.Cache; using Game.DataStorage; using Game.Entities; using System; @@ -99,7 +100,7 @@ namespace Game.Chat if (handler.HasLowerSecurity(null, targetGuid)) return false; - ObjectManager.GetPlayerNameByGUID(targetGuid, out playerOldName); + Global.CharacterCacheStorage.GetCharacterNameByGuid(targetGuid, out playerOldName); } if (!ObjectManager.NormalizePlayerName(ref newName)) @@ -153,13 +154,13 @@ namespace Game.Chat DB.Characters.Execute(stmt); } - Global.WorldMgr.UpdateCharacterInfo(targetGuid, newName); + Global.CharacterCacheStorage.UpdateCharacterData(targetGuid, newName); handler.SendSysMessage(CypherStrings.RenamePlayerWithNewName, playerOldName, newName); Player player = handler.GetPlayer(); if (player) - Log.outCommand(session.GetAccountId(), "GM {0} (Account: {1}) forced rename {2} to player {3} (Account: {4})", player.GetName(), session.GetAccountId(), newName, playerOldName, ObjectManager.GetPlayerAccountIdByGUID(targetGuid)); + Log.outCommand(session.GetAccountId(), "GM {0} (Account: {1}) forced rename {2} to player {3} (Account: {4})", player.GetName(), session.GetAccountId(), newName, playerOldName, Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(targetGuid)); else Log.outCommand(0, "CONSOLE forced rename '{0}' to '{1}' ({2})", playerOldName, newName, targetGuid.ToString()); } @@ -215,7 +216,7 @@ namespace Game.Chat if (!handler.extractPlayerTarget(new StringArguments(nameStr), out target, out targetGuid, out targetName)) return false; - int oldlevel = (int)(target ? target.getLevel() : Player.GetLevelFromDB(targetGuid)); + int oldlevel = (int)(target ? target.getLevel() : Global.CharacterCacheStorage.GetCharacterLevelByGuid(targetGuid)); if (!int.TryParse(levelStr, out int newlevel)) newlevel = oldlevel; @@ -280,7 +281,7 @@ namespace Game.Chat if (!handler.extractPlayerTarget(new StringArguments(playerNameStr), out playerNotUsed, out targetGuid, out targetName)) return false; - CharacterInfo characterInfo = Global.WorldMgr.GetCharacterInfo(targetGuid); + CharacterCacheEntry characterInfo = Global.CharacterCacheStorage.GetCharacterCacheByGuid(targetGuid); if (characterInfo == null) { handler.SendSysMessage(CypherStrings.PlayerNotFound); @@ -323,7 +324,7 @@ namespace Game.Chat Global.WorldMgr.UpdateRealmCharCount(oldAccountId); Global.WorldMgr.UpdateRealmCharCount(newAccountId); - Global.WorldMgr.UpdateCharacterInfoAccount(targetGuid, newAccountId); + Global.CharacterCacheStorage.UpdateCharacterAccountId(targetGuid, newAccountId); handler.SendSysMessage(CypherStrings.ChangeAccountSuccess, targetName, accountName); @@ -467,13 +468,13 @@ namespace Game.Chat } else { - characterGuid = ObjectManager.GetPlayerGUIDByName(characterName); + characterGuid = Global.CharacterCacheStorage.GetCharacterGuidByName(characterName); if (characterGuid.IsEmpty()) { handler.SendSysMessage(CypherStrings.NoPlayer, characterName); return false; } - accountId = ObjectManager.GetPlayerAccountIdByGUID(characterGuid); + accountId = Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(characterGuid); } string accountName; @@ -704,7 +705,7 @@ namespace Game.Chat return; } - if (!ObjectManager.GetPlayerGUIDByName(delInfo.name).IsEmpty()) + if (!Global.CharacterCacheStorage.GetCharacterGuidByName(delInfo.name).IsEmpty()) { handler.SendSysMessage(CypherStrings.CharacterDeletedSkipName, delInfo.name, delInfo.guid.ToString(), delInfo.accountId); return; @@ -716,7 +717,7 @@ namespace Game.Chat stmt.AddValue(2, delInfo.guid.GetCounter()); DB.Characters.Execute(stmt); - Global.WorldMgr.UpdateCharacterInfoDeleted(delInfo.guid, false, delInfo.name); + Global.CharacterCacheStorage.UpdateCharacterInfoDeleted(delInfo.guid, false, delInfo.name); } struct DeletedInfo @@ -749,7 +750,7 @@ namespace Game.Chat if (!handler.extractPlayerTarget(new StringArguments(nameStr), out target, out targetGuid, out targetName)) return false; - int oldlevel = (int)(target ? target.getLevel() : Player.GetLevelFromDB(targetGuid)); + int oldlevel = (int)(target ? target.getLevel() : Global.CharacterCacheStorage.GetCharacterLevelByGuid(targetGuid)); if (!int.TryParse(levelStr, out int addlevel)) addlevel = 1; diff --git a/Source/Game/Chat/Commands/GroupCommands.cs b/Source/Game/Chat/Commands/GroupCommands.cs index e65cf96a9..575a33c74 100644 --- a/Source/Game/Chat/Commands/GroupCommands.cs +++ b/Source/Game/Chat/Commands/GroupCommands.cs @@ -249,7 +249,7 @@ namespace Game.Chat ObjectGuid parseGUID = ObjectGuid.Create(HighGuid.Player, args.NextUInt64()); // ... and try to extract a player out of it. - if (ObjectManager.GetPlayerNameByGUID(parseGUID, out nameTarget)) + if (Global.CharacterCacheStorage.GetCharacterNameByGuid(parseGUID, out nameTarget)) { playerTarget = Global.ObjAccessor.FindPlayer(parseGUID); guidTarget = parseGUID; diff --git a/Source/Game/Chat/Commands/GuildCommands.cs b/Source/Game/Chat/Commands/GuildCommands.cs index ed77f8c16..8b157ef63 100644 --- a/Source/Game/Chat/Commands/GuildCommands.cs +++ b/Source/Game/Chat/Commands/GuildCommands.cs @@ -103,7 +103,7 @@ namespace Game.Chat if (!handler.extractPlayerTarget(args, out target, out targetGuid)) return false; - ulong guildId = target != null ? target.GetGuildId() : Player.GetGuildIdFromDB(targetGuid); + ulong guildId = target != null ? target.GetGuildId() : Global.CharacterCacheStorage.GetCharacterGuildIdByGuid(targetGuid); if (guildId == 0) return false; @@ -130,7 +130,7 @@ namespace Game.Chat if (!handler.extractPlayerTarget(new StringArguments(nameStr), out target, out targetGuid, out target_name)) return false; - ulong guildId = target ? target.GetGuildId() : Player.GetGuildIdFromDB(targetGuid); + ulong guildId = target ? target.GetGuildId() : Global.CharacterCacheStorage.GetCharacterGuildIdByGuid(targetGuid); if (guildId == 0) return false; @@ -210,7 +210,7 @@ namespace Game.Chat handler.SendSysMessage(CypherStrings.GuildInfoName, guild.GetName(), guild.GetId()); // Guild Id + Name string guildMasterName; - if (ObjectManager.GetPlayerNameByGUID(guild.GetLeaderGUID(), out guildMasterName)) + if (Global.CharacterCacheStorage.GetCharacterNameByGuid(guild.GetLeaderGUID(), out guildMasterName)) handler.SendSysMessage(CypherStrings.GuildInfoGuildMaster, guildMasterName, guild.GetLeaderGUID().ToString()); // Guild Master // Format creation date diff --git a/Source/Game/Chat/Commands/LFGCommands.cs b/Source/Game/Chat/Commands/LFGCommands.cs index 1565c725f..20dd3e79b 100644 --- a/Source/Game/Chat/Commands/LFGCommands.cs +++ b/Source/Game/Chat/Commands/LFGCommands.cs @@ -51,7 +51,7 @@ namespace Game.Chat string nameTarget; ObjectGuid parseGUID = ObjectGuid.Create(HighGuid.Player, args.NextUInt64()); - if (ObjectManager.GetPlayerNameByGUID(parseGUID, out nameTarget)) + if (Global.CharacterCacheStorage.GetCharacterNameByGuid(parseGUID, out nameTarget)) { playerTarget = Global.ObjAccessor.FindPlayer(parseGUID); guidTarget = parseGUID; diff --git a/Source/Game/Chat/Commands/ListCommands.cs b/Source/Game/Chat/Commands/ListCommands.cs index 254c5a05c..1120328ef 100644 --- a/Source/Game/Chat/Commands/ListCommands.cs +++ b/Source/Game/Chat/Commands/ListCommands.cs @@ -345,7 +345,7 @@ namespace Game.Chat.Commands PreparedStatement stmt = null; ObjectGuid parseGUID = ObjectGuid.Create(HighGuid.Player, args.NextUInt64()); - if (ObjectManager.GetPlayerNameByGUID(parseGUID, out targetName)) + if (Global.CharacterCacheStorage.GetCharacterNameByGuid(parseGUID, out targetName)) { target = Global.ObjAccessor.FindPlayer(parseGUID); targetGuid = parseGUID; diff --git a/Source/Game/Chat/Commands/MiscCommands.cs b/Source/Game/Chat/Commands/MiscCommands.cs index c94df6507..2bb6eb4da 100644 --- a/Source/Game/Chat/Commands/MiscCommands.cs +++ b/Source/Game/Chat/Commands/MiscCommands.cs @@ -1291,7 +1291,7 @@ namespace Game.Chat ObjectGuid parseGUID = ObjectGuid.Create(HighGuid.Player, args.NextUInt64()); // ... and make sure we get a target, somehow. - if (ObjectManager.GetPlayerNameByGUID(parseGUID, out targetName)) + if (Global.CharacterCacheStorage.GetCharacterNameByGuid(parseGUID, out targetName)) { target = Global.ObjAccessor.FindPlayer(parseGUID); targetGuid = parseGUID; @@ -1673,7 +1673,7 @@ namespace Game.Chat if (!handler.extractPlayerTarget(new StringArguments(nameStr), out target, out targetGuid, out targetName)) return false; - uint accountId = target ? target.GetSession().GetAccountId() : ObjectManager.GetPlayerAccountIdByGUID(targetGuid); + uint accountId = target ? target.GetSession().GetAccountId() : Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(targetGuid); // find only player from same account if any if (!target) @@ -1745,7 +1745,7 @@ namespace Game.Chat if (!handler.extractPlayerTarget(args, out target, out targetGuid, out targetName)) return false; - uint accountId = target ? target.GetSession().GetAccountId() : ObjectManager.GetPlayerAccountIdByGUID(targetGuid); + uint accountId = target ? target.GetSession().GetAccountId() : Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(targetGuid); // find only player from same account if any if (!target) @@ -2259,7 +2259,7 @@ namespace Game.Chat if (!string.IsNullOrEmpty(targetName)) { // Check for offline players - ObjectGuid guid = ObjectManager.GetPlayerGUIDByName(name); + ObjectGuid guid = Global.CharacterCacheStorage.GetCharacterGuidByName(name); if (guid.IsEmpty()) { handler.SendSysMessage(CypherStrings.CommandFreezeWrong); diff --git a/Source/Game/Chat/Commands/TicketCommands.cs b/Source/Game/Chat/Commands/TicketCommands.cs index 7651fc2c2..63a9fc421 100644 --- a/Source/Game/Chat/Commands/TicketCommands.cs +++ b/Source/Game/Chat/Commands/TicketCommands.cs @@ -257,8 +257,8 @@ namespace Game.Chat.Commands return true; } - ObjectGuid targetGuid = ObjectManager.GetPlayerGUIDByName(target); - uint accountId = ObjectManager.GetPlayerAccountIdByGUID(targetGuid); + ObjectGuid targetGuid = Global.CharacterCacheStorage.GetCharacterGuidByName(target); + uint accountId = Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(targetGuid); // Target must exist and have administrative rights if (!Global.AccountMgr.HasPermission(accountId, RBACPermissions.CommandsBeAssignedTicket, Global.WorldMgr.GetRealm().Id.Realm)) { @@ -447,7 +447,7 @@ namespace Game.Chat.Commands else { ObjectGuid guid = ticket.GetAssignedToGUID(); - uint accountId = ObjectManager.GetPlayerAccountIdByGUID(guid); + uint accountId = Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(guid); security = Global.AccountMgr.GetSecurity(accountId, (int)Global.WorldMgr.GetRealm().Id.Realm); } diff --git a/Source/Game/Entities/Corpse.cs b/Source/Game/Entities/Corpse.cs index dda55a057..67ec30a76 100644 --- a/Source/Game/Entities/Corpse.cs +++ b/Source/Game/Entities/Corpse.cs @@ -206,7 +206,7 @@ namespace Game.Entities public bool IsExpired(long t) { // Deleted character - if (Global.WorldMgr.GetCharacterInfo(GetOwnerGUID()) == null) + if (!Global.CharacterCacheStorage.HasCharacterCacheEntry(GetOwnerGUID())) return true; if (m_type == CorpseType.Bones) diff --git a/Source/Game/Entities/Creature/Creature.cs b/Source/Game/Entities/Creature/Creature.cs index deb63a47e..95cdef750 100644 --- a/Source/Game/Entities/Creature/Creature.cs +++ b/Source/Game/Entities/Creature/Creature.cs @@ -129,7 +129,7 @@ namespace Game.Entities m_corpseRemoveTime = Time.UnixTime; setDeathState(DeathState.Dead); RemoveAllAuras(); - UpdateObjectVisibility(); + DestroyForNearbyPlayers(); // old UpdateObjectVisibility() loot.clear(); uint respawnDelay = m_respawnDelay; if (IsAIEnabled) diff --git a/Source/Game/Entities/GameObject/GameObject.cs b/Source/Game/Entities/GameObject/GameObject.cs index d7b739dd8..59cb6dfcb 100644 --- a/Source/Game/Entities/GameObject/GameObject.cs +++ b/Source/Game/Entities/GameObject/GameObject.cs @@ -784,7 +784,7 @@ namespace Game.Entities if (!m_spawnedByDefault) { m_respawnTime = 0; - UpdateObjectVisibility(); + DestroyForNearbyPlayers(); // old UpdateObjectVisibility() return; } @@ -794,8 +794,7 @@ namespace Game.Entities if (WorldConfig.GetBoolValue(WorldCfg.SaveRespawnTimeImmediately)) SaveRespawnTime(); - UpdateObjectVisibility(); - + DestroyForNearbyPlayers(); // old UpdateObjectVisibility() break; } } diff --git a/Source/Game/Entities/Player/Player.DB.cs b/Source/Game/Entities/Player/Player.DB.cs index 7d52a4ff1..dafb8a91e 100644 --- a/Source/Game/Entities/Player/Player.DB.cs +++ b/Source/Game/Entities/Player/Player.DB.cs @@ -20,6 +20,7 @@ using Framework.Constants; using Framework.Database; using Game.Arenas; using Game.BattleGrounds; +using Game.Cache; using Game.DataStorage; using Game.Garrisons; using Game.Groups; @@ -630,6 +631,13 @@ namespace Game.Entities _currencyStorage.Add(currencyID, cur); } while (result.NextRow()); } + void LoadActions(SQLResult result) + { + if (!result.IsEmpty()) + _LoadActions(result); + + SendActionButtons(1); + } void _LoadActions(SQLResult result) { m_actionButtons.Clear(); @@ -2333,7 +2341,7 @@ namespace Game.Entities if (result.IsEmpty()) { string name; - ObjectManager.GetPlayerNameByGUID(guid, out name); + Global.CharacterCacheStorage.GetCharacterNameByGuid(guid, out name); Log.outError(LogFilter.Player, "Player {0} {1} not found in table `characters`, can't load. ", name, guid.ToString()); return false; } @@ -3462,26 +3470,6 @@ namespace Game.Entities DB.Characters.Execute(stmt); } - public static uint GetGuildIdFromDB(ObjectGuid guid) - { - PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_GUILD_MEMBER); - stmt.AddValue(0, guid.GetCounter()); - SQLResult result = DB.Characters.Query(stmt); - if (!result.IsEmpty()) - return result.Read(0); - - return 0; - } - public static byte GetRankFromDB(ObjectGuid guid) - { - PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_GUILD_MEMBER); - stmt.AddValue(0, guid.GetCounter()); - SQLResult result = DB.Characters.Query(stmt); - if (!result.IsEmpty()) - return result.Read(1); - - return 0; - } public static uint GetZoneIdFromDB(ObjectGuid guid) { ulong guidLow = guid.GetCounter(); @@ -3527,17 +3515,6 @@ namespace Game.Entities return zone; } - public static uint GetLevelFromDB(ObjectGuid guid) - { - PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHAR_LEVEL); - stmt.AddValue(0, guid.GetCounter()); - SQLResult result = DB.Characters.Query(stmt); - - if (result.IsEmpty()) - return 0; - - return result.Read(0); - } public static void RemovePetitionsAndSigns(ObjectGuid guid) { PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PETITION_SIG_BY_GUID); @@ -3582,18 +3559,21 @@ namespace Game.Entities // Convert guid to low GUID for CharacterNameData, but also other methods on success ulong guid = playerGuid.GetCounter(); CharDeleteMethod charDelete_method = (CharDeleteMethod)WorldConfig.GetIntValue(WorldCfg.ChardeleteMethod); + CharacterCacheEntry characterInfo = Global.CharacterCacheStorage.GetCharacterCacheByGuid(playerGuid); + string name = ""; + if (characterInfo != null) + name = characterInfo.Name; - CharacterInfo characterInfo; if (deleteFinally) charDelete_method = CharDeleteMethod.Remove; - else if ((characterInfo = Global.WorldMgr.GetCharacterInfo(playerGuid)) != null) // To avoid a Select, we select loaded data. If it doesn't exist, return. + else if (characterInfo != null) // To avoid a Select, we select loaded data. If it doesn't exist, return. { // Define the required variables uint charDeleteMinLvl; - if (characterInfo.ClassID == Class.Deathknight) + if (characterInfo.ClassId == Class.Deathknight) charDeleteMinLvl = WorldConfig.GetUIntValue(WorldCfg.ChardeleteDeathKnightMinLevel); - else if (characterInfo.ClassID == Class.DemonHunter) + else if (characterInfo.ClassId == Class.DemonHunter) charDeleteMinLvl = WorldConfig.GetUIntValue(WorldCfg.ChardeleteDemonHunterMinLevel); else charDeleteMinLvl = WorldConfig.GetUIntValue(WorldCfg.ChardeleteMinLevel); @@ -3605,7 +3585,7 @@ namespace Game.Entities } SQLTransaction trans = new SQLTransaction(); - uint guildId = GetGuildIdFromDB(playerGuid); + ulong guildId = Global.CharacterCacheStorage.GetCharacterGuildIdByGuid(playerGuid); if (guildId != 0) { Guild guild = Global.GuildMgr.GetGuildById(guildId); @@ -3714,7 +3694,7 @@ namespace Game.Entities stmt.AddValue(0, mail_id); trans.Append(stmt); - uint pl_account = ObjectManager.GetPlayerAccountIdByGUID(ObjectGuid.Create(HighGuid.Player, guid)); + uint pl_account = Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(ObjectGuid.Create(HighGuid.Player, guid)); draft.AddMoney(money).SendReturnToSender(pl_account, guid, sender, trans); } @@ -3955,7 +3935,7 @@ namespace Game.Entities Garrison.DeleteFromDB(guid, trans); - Global.WorldMgr.DeleteCharacterInfo(playerGuid); + Global.CharacterCacheStorage.DeleteCharacterCacheEntry(playerGuid, name); break; } // The character gets unlinked from the account, the name gets freed up and appears as deleted ingame @@ -3965,7 +3945,7 @@ namespace Game.Entities stmt.AddValue(0, guid); trans.Append(stmt); - Global.WorldMgr.UpdateCharacterInfoDeleted(playerGuid, true); + Global.CharacterCacheStorage.UpdateCharacterInfoDeleted(playerGuid, true); break; } default: diff --git a/Source/Game/Entities/Player/Player.PvP.cs b/Source/Game/Entities/Player/Player.PvP.cs index 56fdf3ac2..e554864b6 100644 --- a/Source/Game/Entities/Player/Player.PvP.cs +++ b/Source/Game/Entities/Player/Player.PvP.cs @@ -20,6 +20,7 @@ using Framework.Database; using Game.Arenas; using Game.BattleFields; using Game.BattleGrounds; +using Game.Cache; using Game.DataStorage; using Game.Network.Packets; using Game.PvP; @@ -887,31 +888,15 @@ namespace Game.Entities SetArenaTeamInfoField(slot, ArenaTeamInfoType.Type, type); } - public static uint GetArenaTeamIdFromDB(ObjectGuid guid, byte type) - { - PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_ARENA_TEAM_ID_BY_PLAYER_GUID); - stmt.AddValue(0, guid.GetCounter()); - stmt.AddValue(1, type); - SQLResult result = DB.Characters.Query(stmt); - - if (result.IsEmpty()) - return 0; - - return result.Read(0); - } - public static void LeaveAllArenaTeams(ObjectGuid guid) { - PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PLAYER_ARENA_TEAMS); - stmt.AddValue(0, guid.GetCounter()); - SQLResult result = DB.Characters.Query(stmt); - - if (result.IsEmpty()) + CharacterCacheEntry characterInfo = Global.CharacterCacheStorage.GetCharacterCacheByGuid(guid); + if (characterInfo == null) return; - do + for (byte i = 0; i < SharedConst.MaxArenaSlot; ++i) { - uint arenaTeamId = result.Read(0); + uint arenaTeamId = characterInfo.ArenaTeamId[i]; if (arenaTeamId != 0) { ArenaTeam arenaTeam = Global.ArenaTeamMgr.GetArenaTeamById(arenaTeamId); @@ -919,7 +904,6 @@ namespace Game.Entities arenaTeam.DelMember(guid, true); } } - while (result.NextRow()); } public uint GetArenaTeamId(byte slot) { return 0; } public uint GetArenaPersonalRating(byte slot) { return m_activePlayerData.PvpInfo[slot].Rating; } diff --git a/Source/Game/Entities/Player/Player.Quest.cs b/Source/Game/Entities/Player/Player.Quest.cs index 02faff1aa..7f54f66f2 100644 --- a/Source/Game/Entities/Player/Player.Quest.cs +++ b/Source/Game/Entities/Player/Player.Quest.cs @@ -1626,12 +1626,12 @@ namespace Game.Entities if (!qInfo.IsSeasonal() || m_seasonalquests.Empty()) return true; - ushort eventId = Global.GameEventMgr.GetEventIdForQuest(qInfo); - if (!m_seasonalquests.ContainsKey(eventId) || m_seasonalquests[eventId].Empty()) + var list = m_seasonalquests.LookupByKey(qInfo.GetEventIdForQuest()); + if (list == null || list.Empty()) return true; // if not found in cooldown list - return !m_seasonalquests[eventId].Contains(qInfo.Id); + return !list.Contains(qInfo.Id); } public bool SatisfyQuestMonth(Quest qInfo, bool msg) @@ -1719,13 +1719,7 @@ namespace Game.Entities if (qInfo != null) { if (qInfo.IsSeasonal() && !qInfo.IsRepeatable()) - { - ushort eventId = Global.GameEventMgr.GetEventIdForQuest(qInfo); - if (m_seasonalquests.ContainsKey(eventId)) - return m_seasonalquests[eventId].Contains(quest_id); - - return false; - } + return !SatisfyQuestSeasonal(qInfo, false); // for repeatable quests: rewarded field is set after first reward only to prevent getting XP more than once if (!qInfo.IsRepeatable()) @@ -1748,12 +1742,9 @@ namespace Game.Entities if (quest != null) { if (quest.IsSeasonal() && !quest.IsRepeatable()) - { - ushort eventId = Global.GameEventMgr.GetEventIdForQuest(quest); - if (!m_seasonalquests.ContainsKey(eventId) || !m_seasonalquests[eventId].Contains(questId)) - return QuestStatus.None; - } - if (!quest.IsRepeatable() && m_RewardedQuests.Contains(questId)) + return SatisfyQuestSeasonal(quest, false) ? QuestStatus.None : QuestStatus.Rewarded; + + if (!quest.IsRepeatable() && IsQuestRewarded(questId)) return QuestStatus.Rewarded; } } @@ -3049,7 +3040,7 @@ namespace Game.Entities if (quest == null) return; - m_seasonalquests.Add(Global.GameEventMgr.GetEventIdForQuest(quest), quest_id); + m_seasonalquests.Add(quest.GetEventIdForQuest(), quest_id); m_SeasonalQuestChanged = true; } diff --git a/Source/Game/Entities/Player/Player.Talents.cs b/Source/Game/Entities/Player/Player.Talents.cs index 0c360f533..fb7a1e475 100644 --- a/Source/Game/Entities/Player/Player.Talents.cs +++ b/Source/Game/Entities/Player/Player.Talents.cs @@ -381,9 +381,15 @@ namespace Game.Entities PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHARACTER_ACTIONS_SPEC); stmt.AddValue(0, GetGUID().GetCounter()); stmt.AddValue(1, GetActiveTalentGroup()); - _LoadActions(DB.Characters.Query(stmt)); - SendActionButtons(1); + WorldSession mySess = GetSession(); + mySess.GetQueryProcessor().AddQuery(DB.Characters.AsyncQuery(stmt).WithCallback(result => + { + // in case player logs out before db response (player would be deleted in that case) + Player thisPlayer = mySess.GetPlayer(); + if (thisPlayer != null) + thisPlayer.LoadActions(result); + })); UpdateDisplayPower(); PowerType pw = GetPowerType(); diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index 33c34ee3b..67dfe0655 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -791,7 +791,7 @@ namespace Game.Entities { base.DestroyForPlayer(target); - for (byte i = 0; i < InventorySlots.BagEnd; ++i) + for (byte i = 0; i < EquipmentSlot.End; ++i) { if (m_items[i] == null) continue; @@ -5279,6 +5279,8 @@ namespace Game.Entities SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.GuildGUID), ObjectGuid.Empty); RemovePlayerFlag(PlayerFlags.GuildLevelEnabled); } + + Global.CharacterCacheStorage.UpdateCharacterGuildId(GetGUID(), guildId); } public void SetGuildRank(byte rankId) { SetUpdateFieldValue(m_values.ModifyValue(m_playerData).ModifyValue(m_playerData.GuildRankID), rankId); } public uint GetGuildRank() { return m_playerData.GuildRankID; } diff --git a/Source/Game/Entities/Unit/Unit.Spells.cs b/Source/Game/Entities/Unit/Unit.Spells.cs index afc4ce7ff..95fda40e3 100644 --- a/Source/Game/Entities/Unit/Unit.Spells.cs +++ b/Source/Game/Entities/Unit/Unit.Spells.cs @@ -986,10 +986,7 @@ namespace Game.Entities // Increase hit chance from attacker SPELL_AURA_MOD_SPELL_HIT_CHANCE and attacker ratings HitChance += (int)(modHitChance * 100.0f); - if (HitChance < 100) - HitChance = 100; - else if (HitChance > 10000) - HitChance = 10000; + MathFunctions.RoundToInterval(ref HitChance, 0, 10000); int tmp = 10000 - HitChance; diff --git a/Source/Game/Entities/Unit/Unit.cs b/Source/Game/Entities/Unit/Unit.cs index 8063bcf71..8f7127ccf 100644 --- a/Source/Game/Entities/Unit/Unit.cs +++ b/Source/Game/Entities/Unit/Unit.cs @@ -2073,7 +2073,8 @@ namespace Game.Entities { if (player.GetGroup()) player.SetGroupUpdateFlag(GroupUpdateFlags.Level); - Global.WorldMgr.UpdateCharacterInfoLevel(ToPlayer().GetGUID(), (byte)lvl); + + Global.CharacterCacheStorage.UpdateCharacterLevel(ToPlayer().GetGUID(), (byte)lvl); } } public uint getLevel() { return m_unitData.Level; } diff --git a/Source/Game/Events/GameEventManager.cs b/Source/Game/Events/GameEventManager.cs index 8a3d32c8b..0aedc1f73 100644 --- a/Source/Game/Events/GameEventManager.cs +++ b/Source/Game/Events/GameEventManager.cs @@ -714,7 +714,8 @@ namespace Game uint questId = result.Read(0); ushort eventEntry = result.Read(1); // @todo Change to byte - if (Global.ObjectMgr.GetQuestTemplate(questId) == null) + Quest questTemplate = Global.ObjectMgr.GetQuestTemplate(questId); + if (questTemplate == null) { Log.outError(LogFilter.Sql, "`game_event_seasonal_questrelation` quest id ({0}) does not exist in `quest_template`", questId); continue; @@ -726,7 +727,7 @@ namespace Game continue; } - _questToEventLinks[questId] = eventEntry; + questTemplate.SetEventIdForQuest(eventEntry); ++count; } while (result.NextRow()); @@ -1562,14 +1563,6 @@ namespace Game }); } - public ushort GetEventIdForQuest(Quest quest) - { - if (quest == null) - return 0; - - return _questToEventLinks.LookupByKey(quest.Id); - } - public bool IsHolidayActive(HolidayIds id) { if (id == HolidayIds.None) @@ -1610,7 +1603,6 @@ namespace Game Dictionary mQuestToEventConditions = new Dictionary(); List<(ulong guid, ulong npcflag)>[] mGameEventNPCFlags; List m_ActiveEvents = new List(); - Dictionary _questToEventLinks = new Dictionary(); bool isSystemInit; public List[] mGameEventCreatureGuids; diff --git a/Source/Game/Globals/Global.cs b/Source/Game/Globals/Global.cs index 4a4abebbe..a9fc4cb61 100644 --- a/Source/Game/Globals/Global.cs +++ b/Source/Game/Globals/Global.cs @@ -35,6 +35,7 @@ using Game.Scenarios; using Game.Scripting; using Game.SupportSystem; using Game.Services; +using Game.Cache; public static class Global { @@ -93,6 +94,7 @@ public static class Global public static AreaTriggerDataStorage AreaTriggerDataStorage { get { return AreaTriggerDataStorage.Instance; } } public static CharacterTemplateDataStorage CharacterTemplateDataStorage { get { return CharacterTemplateDataStorage.Instance; } } public static ConversationDataStorage ConversationDataStorage { get { return ConversationDataStorage.Instance; } } + public static CharacterCache CharacterCacheStorage { get { return CharacterCache.Instance; } } //Misc public static ConditionManager ConditionMgr { get { return ConditionManager.Instance; } } diff --git a/Source/Game/Globals/ObjectAccessor.cs b/Source/Game/Globals/ObjectAccessor.cs index c74ef480e..e258472bf 100644 --- a/Source/Game/Globals/ObjectAccessor.cs +++ b/Source/Game/Globals/ObjectAccessor.cs @@ -201,7 +201,11 @@ public class ObjectAccessor : Singleton return player; } - + public Player FindPlayerByLowGUID(ulong lowguid) + { + ObjectGuid guid = ObjectGuid.Create(HighGuid.Player, lowguid); + return FindPlayer(guid); + } // this returns Player even if he is not in world, for example teleporting public Player FindConnectedPlayer(ObjectGuid guid) { diff --git a/Source/Game/Globals/ObjectManager.cs b/Source/Game/Globals/ObjectManager.cs index dc0f04483..c3541941b 100644 --- a/Source/Game/Globals/ObjectManager.cs +++ b/Source/Game/Globals/ObjectManager.cs @@ -193,74 +193,6 @@ namespace Game dynamicFlags = data.dynamicflags; } } - public static ObjectGuid GetPlayerGUIDByName(string name) - { - PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_GUID_BY_NAME); - stmt.AddValue(0, name); - SQLResult result = DB.Characters.Query(stmt); - - if (!result.IsEmpty()) - return ObjectGuid.Create(HighGuid.Player, result.Read(0)); - - return ObjectGuid.Empty; - } - public static bool GetPlayerNameByGUID(ObjectGuid guid, out string name) - { - name = ""; - - Player player = Global.ObjAccessor.FindConnectedPlayer(guid); - if (player) - { - name = player.GetName(); - return true; - } - - CharacterInfo characterInfo = Global.WorldMgr.GetCharacterInfo(guid); - if (characterInfo == null) - return false; - - name = characterInfo.Name; - return true; - } - public static bool GetPlayerNameAndClassByGUID(ObjectGuid guid, out string name, out byte _class) - { - name = ""; - _class = 0; - - Player player = Global.ObjAccessor.FindConnectedPlayer(guid); - if (player) - { - name = player.GetName(); - _class = (byte)player.GetClass(); - return true; - } - - CharacterInfo characterInfo = Global.WorldMgr.GetCharacterInfo(guid); - if (characterInfo != null) - { - name = characterInfo.Name; - _class = (byte)characterInfo.ClassID; - return true; - } - - return false; - } - public static Team GetPlayerTeamByGUID(ObjectGuid guid) - { - CharacterInfo characterInfo = Global.WorldMgr.GetCharacterInfo(guid); - if (characterInfo != null) - return Player.TeamForRace(characterInfo.RaceID); - - return 0; - } - public static uint GetPlayerAccountIdByGUID(ObjectGuid guid) - { - CharacterInfo characterInfo = Global.WorldMgr.GetCharacterInfo(guid); - if (characterInfo != null) - return characterInfo.AccountId; - - return 0; - } public static ResponseCodes CheckPlayerName(string name, LocaleConstant locale, bool create = false) { diff --git a/Source/Game/Groups/Group.cs b/Source/Game/Groups/Group.cs index 84e46f290..43dbf2c88 100644 --- a/Source/Game/Groups/Group.cs +++ b/Source/Game/Groups/Group.cs @@ -125,7 +125,7 @@ namespace Game.Groups m_leaderGuid = ObjectGuid.Create(HighGuid.Player, field.Read(0)); // group leader not exist - if (!ObjectManager.GetPlayerNameByGUID(m_leaderGuid, out m_leaderName)) + if (!Global.CharacterCacheStorage.GetCharacterNameByGuid(m_leaderGuid, out m_leaderName)) return; m_lootMethod = (LootMethod)field.Read(1); @@ -155,7 +155,7 @@ namespace Game.Groups member.guid = ObjectGuid.Create(HighGuid.Player, guidLow); // skip non-existed member - if (!ObjectManager.GetPlayerNameAndClassByGUID(member.guid, out member.name, out member._class)) + if (!Global.CharacterCacheStorage.GetCharacterNameAndClassByGUID(member.guid, out member.name, out member._class)) { PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_GROUP_MEMBER); stmt.AddValue(0, guidLow); diff --git a/Source/Game/Guilds/Guild.cs b/Source/Game/Guilds/Guild.cs index 8689b02fb..41a601b0f 100644 --- a/Source/Game/Guilds/Guild.cs +++ b/Source/Game/Guilds/Guild.cs @@ -625,7 +625,7 @@ namespace Game.Guilds { Player player = session.GetPlayer(); if (!WorldConfig.GetBoolValue(WorldCfg.AllowTwoSideInteractionGuild) && - player.GetTeam() != ObjectManager.GetPlayerTeamByGUID(GetLeaderGUID())) + player.GetTeam() != Global.CharacterCacheStorage.GetCharacterTeamByGuid(GetLeaderGUID())) return; AddMember(null, player.GetGUID()); @@ -1209,12 +1209,14 @@ namespace Game.Guilds public bool LoadMemberFromDB(SQLFields field) { ulong lowguid = field.Read(1); - Member member = new Member(m_id, ObjectGuid.Create(HighGuid.Player, lowguid), field.Read(2)); + ObjectGuid playerGuid = ObjectGuid.Create(HighGuid.Player, lowguid); + Member member = new Member(m_id, playerGuid, field.Read(2)); if (!member.LoadFromDB(field)) { _DeleteMemberFromDB(null, lowguid); return false; } + Global.CharacterCacheStorage.UpdateCharacterGuildId(playerGuid, GetId()); m_members[member.GetGUID()] = member; return true; } @@ -1477,7 +1479,7 @@ namespace Game.Guilds return; } - uint level = Player.GetLevelFromDB(member.GetGUID()); + uint level = Global.CharacterCacheStorage.GetCharacterLevelByGuid(member.GetGUID()); if (member.GetGUID() != session.GetPlayer().GetGUID() && level >= minLevel && level <= maxLevel && member.IsRankNotLower(minRank)) packet.Invites.Add(new CalendarEventInitialInviteInfo(member.GetGUID(), (byte)level)); @@ -1495,7 +1497,7 @@ namespace Game.Guilds if (player.GetGuildId() != 0) return false; } - else if (Player.GetGuildIdFromDB(guid) != 0) + else if (Global.CharacterCacheStorage.GetCharacterGuildIdByGuid(guid) != 0) return false; // Remove all player signs from another petitions @@ -1548,6 +1550,7 @@ namespace Game.Guilds return false; m_members[guid] = member; + Global.CharacterCacheStorage.UpdateCharacterGuildId(guid, GetId()); } member.SaveToDB(trans); @@ -1617,6 +1620,8 @@ namespace Game.Guilds foreach (var entry in CliDB.GuildPerkSpellsStorage.Values) player.RemoveSpell(entry.SpellID, false, false); } + else + Global.CharacterCacheStorage.UpdateCharacterGuildId(guid, 0); _DeleteMemberFromDB(trans, guid.GetCounter()); if (!isDisbanding) diff --git a/Source/Game/Handlers/AuctionHandler.cs b/Source/Game/Handlers/AuctionHandler.cs index 6710856e2..21105e99c 100644 --- a/Source/Game/Handlers/AuctionHandler.cs +++ b/Source/Game/Handlers/AuctionHandler.cs @@ -384,7 +384,7 @@ namespace Game // impossible have online own another character (use this for speedup check in case online owner) ObjectGuid ownerGuid = ObjectGuid.Create(HighGuid.Player, auction.owner); Player auction_owner = Global.ObjAccessor.FindPlayer(ownerGuid); - if (!auction_owner && ObjectManager.GetPlayerAccountIdByGUID(ownerGuid) == player.GetSession().GetAccountId()) + if (!auction_owner && Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(ownerGuid) == player.GetSession().GetAccountId()) { //you cannot bid your another character auction: SendAuctionCommandResult(null, AuctionAction.PlaceBid, AuctionError.BidOwn); diff --git a/Source/Game/Handlers/CalendarHandler.cs b/Source/Game/Handlers/CalendarHandler.cs index 1ebedefc5..a4cadbf6f 100644 --- a/Source/Game/Handlers/CalendarHandler.cs +++ b/Source/Game/Handlers/CalendarHandler.cs @@ -17,6 +17,7 @@ using Framework.Constants; using Framework.Database; +using Game.Cache; using Game.Entities; using Game.Guilds; using Game.Maps; @@ -255,14 +256,16 @@ namespace Game else { // Invitee offline, get data from database - PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_GUID_RACE_ACC_BY_NAME); - stmt.AddValue(0, calendarEventInvite.Name); - SQLResult result = DB.Characters.Query(stmt); - if (!result.IsEmpty()) + ObjectGuid guid = Global.CharacterCacheStorage.GetCharacterGuidByName(calendarEventInvite.Name); + if (!guid.IsEmpty()) { - inviteeGuid = ObjectGuid.Create(HighGuid.Player, result.Read(0)); - inviteeTeam = Player.TeamForRace((Race)result.Read(1)); - inviteeGuildId = Player.GetGuildIdFromDB(inviteeGuid); + CharacterCacheEntry characterInfo = Global.CharacterCacheStorage.GetCharacterCacheByGuid(guid); + if (characterInfo != null) + { + inviteeGuid = guid; + inviteeTeam = Player.TeamForRace(characterInfo.RaceId); + inviteeGuildId = characterInfo.GuildId; + } } } diff --git a/Source/Game/Handlers/CharacterHandler.cs b/Source/Game/Handlers/CharacterHandler.cs index b396a158d..cc94b613c 100644 --- a/Source/Game/Handlers/CharacterHandler.cs +++ b/Source/Game/Handlers/CharacterHandler.cs @@ -18,6 +18,7 @@ using Framework.Collections; using Framework.Constants; using Framework.Database; +using Game.Cache; using Game.DataStorage; using Game.Entities; using Game.Groups; @@ -97,8 +98,8 @@ namespace Game if (!charInfo.Flags.HasAnyFlag(CharacterFlags.CharacterLockedForTransfer | CharacterFlags.LockedByBilling)) _legitCharacters.Add(charInfo.Guid); - if (!Global.WorldMgr.HasCharacterInfo(charInfo.Guid)) // This can happen if characters are inserted into the database manually. Core hasn't loaded name data yet. - Global.WorldMgr.AddCharacterInfo(charInfo.Guid, GetAccountId(), charInfo.Name, charInfo.Sex, charInfo.RaceId, (byte)charInfo.ClassId, charInfo.Level, false); + if (!Global.CharacterCacheStorage.HasCharacterCacheEntry(charInfo.Guid)) // This can happen if characters are inserted into the database manually. Core hasn't loaded name data yet. + Global.CharacterCacheStorage.AddCharacterCacheEntry(charInfo.Guid, GetAccountId(), charInfo.Name, charInfo.Sex, charInfo.RaceId, (byte)charInfo.ClassId, charInfo.Level, false); if (charInfo.ClassId == Class.DemonHunter) demonHunterCount++; @@ -161,8 +162,8 @@ namespace Game Log.outInfo(LogFilter.Network, "Loading undeleted char guid {0} from account {1}.", charInfo.Guid.ToString(), GetAccountId()); - if (!Global.WorldMgr.HasCharacterInfo(charInfo.Guid)) // This can happen if characters are inserted into the database manually. Core hasn't loaded name data yet. - Global.WorldMgr.AddCharacterInfo(charInfo.Guid, GetAccountId(), charInfo.Name, charInfo.Sex, charInfo.RaceId, (byte)charInfo.ClassId, charInfo.Level, true); + if (!Global.CharacterCacheStorage.HasCharacterCacheEntry(charInfo.Guid)) // This can happen if characters are inserted into the database manually. Core hasn't loaded name data yet. + Global.CharacterCacheStorage.AddCharacterCacheEntry(charInfo.Guid, GetAccountId(), charInfo.Name, charInfo.Sex, charInfo.RaceId, (byte)charInfo.ClassId, charInfo.Level, true); charEnum.Characters.Add(charInfo); } @@ -477,7 +478,7 @@ namespace Game Log.outInfo(LogFilter.Player, "Account: {0} (IP: {1}) Create Character: {2} {3}", GetAccountId(), GetRemoteAddress(), createInfo.Name, newChar.GetGUID().ToString()); Global.ScriptMgr.OnPlayerCreate(newChar); - Global.WorldMgr.AddCharacterInfo(newChar.GetGUID(), GetAccountId(), newChar.GetName(), newChar.m_playerData.NativeSex, (byte)newChar.GetRace(), (byte)newChar.GetClass(), (byte)newChar.getLevel(), false); + Global.CharacterCacheStorage.AddCharacterCacheEntry(newChar.GetGUID(), GetAccountId(), newChar.GetName(), newChar.m_playerData.NativeSex, (byte)newChar.GetRace(), (byte)newChar.GetClass(), (byte)newChar.getLevel(), false); newChar.CleanupsBeforeDelete(); } @@ -498,13 +499,20 @@ namespace Game [WorldPacketHandler(ClientOpcodes.CharDelete, Status = SessionStatus.Authed)] void HandleCharDelete(CharDelete charDelete) { + // Initiating + uint initAccountId = GetAccountId(); + // can't delete loaded character if (Global.ObjAccessor.FindPlayer(charDelete.Guid)) + { + Global.ScriptMgr.OnPlayerFailedDelete(charDelete.Guid, initAccountId); return; + } // is guild leader if (Global.GuildMgr.GetGuildByLeader(charDelete.Guid)) { + Global.ScriptMgr.OnPlayerFailedDelete(charDelete.Guid, initAccountId); SendCharDelete(ResponseCodes.CharDeleteFailedGuildLeader); return; } @@ -512,14 +520,15 @@ namespace Game // is arena team captain if (Global.ArenaTeamMgr.GetArenaTeamByCaptain(charDelete.Guid) != null) { + Global.ScriptMgr.OnPlayerFailedDelete(charDelete.Guid, initAccountId); SendCharDelete(ResponseCodes.CharDeleteFailedArenaCaptain); return; } - CharacterInfo characterInfo = Global.WorldMgr.GetCharacterInfo(charDelete.Guid); + CharacterCacheEntry characterInfo = Global.CharacterCacheStorage.GetCharacterCacheByGuid(charDelete.Guid); if (characterInfo == null) { - //Global.ScriptMgr.OnPlayerFailedDelete(charDelete.Guid, initAccountId); + Global.ScriptMgr.OnPlayerFailedDelete(charDelete.Guid, initAccountId); return; } @@ -529,11 +538,17 @@ namespace Game // prevent deleting other players' characters using cheating tools if (accountId != GetAccountId()) + { + Global.ScriptMgr.OnPlayerFailedDelete(charDelete.Guid, initAccountId); return; + } string IP_str = GetRemoteAddress(); Log.outInfo(LogFilter.Player, "Account: {0}, IP: {1} deleted character: {2}, {3}, Level: {4}", accountId, IP_str, name, charDelete.Guid.ToString(), level); - Global.ScriptMgr.OnPlayerDelete(charDelete.Guid); + + // To prevent hook failure, place hook before removing reference from DB + Global.ScriptMgr.OnPlayerDelete(charDelete.Guid, initAccountId); // To prevent race conditioning, but as it also makes sense, we hand the accountId over for successful delete. + // Shouldn't interfere with character deletion though Global.GuildFinderMgr.RemoveAllMembershipRequestsFromPlayer(charDelete.Guid); Global.CalendarMgr.RemoveAllPlayerEventsAndInvites(charDelete.Guid); @@ -1038,7 +1053,7 @@ namespace Game SendCharRename(ResponseCodes.Success, renameInfo); - Global.WorldMgr.UpdateCharacterInfo(renameInfo.Guid, renameInfo.NewName); + Global.CharacterCacheStorage.UpdateCharacterData(renameInfo.Guid, renameInfo.NewName); } [WorldPacketHandler(ClientOpcodes.SetPlayerDeclinedNames, Status = SessionStatus.Authed)] @@ -1046,7 +1061,7 @@ namespace Game { // not accept declined names for unsupported languages string name; - if (!ObjectManager.GetPlayerNameByGUID(packet.Player, out name)) + if (!Global.CharacterCacheStorage.GetCharacterNameByGuid(packet.Player, out name)) { SendSetPlayerDeclinedNamesResult(DeclinedNameResult.Error, packet.Player); return; @@ -1248,7 +1263,7 @@ namespace Game // character with this name already exist // @todo: make async - ObjectGuid newGuid = ObjectManager.GetPlayerGUIDByName(customizeInfo.CharName); + ObjectGuid newGuid = Global.CharacterCacheStorage.GetCharacterGuidByName(customizeInfo.CharName); if (!newGuid.IsEmpty()) { if (newGuid != customizeInfo.CharGUID) @@ -1296,7 +1311,7 @@ namespace Game DB.Characters.CommitTransaction(trans); - Global.WorldMgr.UpdateCharacterInfo(customizeInfo.CharGUID, customizeInfo.CharName, customizeInfo.SexID); + Global.CharacterCacheStorage.UpdateCharacterData(customizeInfo.CharGUID, customizeInfo.CharName, (byte)customizeInfo.SexID); SendCharCustomize(ResponseCodes.Success, customizeInfo); @@ -1479,7 +1494,7 @@ namespace Game } // get the players old (at this moment current) race - CharacterInfo characterInfo = Global.WorldMgr.GetCharacterInfo(factionChangeInfo.Guid); + CharacterCacheEntry characterInfo = Global.CharacterCacheStorage.GetCharacterCacheByGuid(factionChangeInfo.Guid); if (characterInfo == null) { SendCharFactionChange(ResponseCodes.CharCreateError, factionChangeInfo); @@ -1487,8 +1502,8 @@ namespace Game } string oldName = characterInfo.Name; - Race oldRace = characterInfo.RaceID; - Class playerClass = characterInfo.ClassID; + Race oldRace = characterInfo.RaceId; + Class playerClass = characterInfo.ClassId; byte level = characterInfo.Level; if (Global.ObjectMgr.GetPlayerInfo(factionChangeInfo.RaceID, playerClass) == null) @@ -1559,7 +1574,7 @@ namespace Game } // character with this name already exist - ObjectGuid newGuid = ObjectManager.GetPlayerGUIDByName(factionChangeInfo.Name); + ObjectGuid newGuid = Global.CharacterCacheStorage.GetCharacterGuidByName(factionChangeInfo.Name); if (!newGuid.IsEmpty()) { if (newGuid != factionChangeInfo.Guid) @@ -1625,7 +1640,7 @@ namespace Game trans.Append(stmt); } - Global.WorldMgr.UpdateCharacterInfo(factionChangeInfo.Guid, factionChangeInfo.Name, factionChangeInfo.SexID, factionChangeInfo.RaceID); + Global.CharacterCacheStorage.UpdateCharacterData(factionChangeInfo.Guid, factionChangeInfo.Name, (byte)factionChangeInfo.SexID, (byte)factionChangeInfo.RaceID); if (oldRace != factionChangeInfo.RaceID) { @@ -1730,20 +1745,12 @@ namespace Game trans.Append(stmt); } - // @todo: make this part asynch if (!WorldConfig.GetBoolValue(WorldCfg.AllowTwoSideInteractionGuild)) { // Reset guild - stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_GUILD_MEMBER); - stmt.AddValue(0, lowGuid); - - result = DB.Characters.Query(stmt); - if (!result.IsEmpty()) - { - Guild guild = Global.GuildMgr.GetGuildById(result.Read(0)); - if (guild) - guild.DeleteMember(trans, factionChangeInfo.Guid, false, false, true); - } + Guild guild = Global.GuildMgr.GetGuildById(characterInfo.GuildId); + if (guild != null) + guild.DeleteMember(trans, factionChangeInfo.Guid, false, false, true); Player.LeaveAllArenaTeams(factionChangeInfo.Guid); } @@ -2132,7 +2139,7 @@ namespace Game stmt.AddValue(0, GetBattlenetAccountId()); DB.Login.Execute(stmt); - Global.WorldMgr.UpdateCharacterInfoDeleted(undeleteInfo.CharacterGuid, false, undeleteInfo.Name); + Global.CharacterCacheStorage.UpdateCharacterInfoDeleted(undeleteInfo.CharacterGuid, false, undeleteInfo.Name); SendUndeleteCharacterResponse(CharacterUndeleteResult.Ok, undeleteInfo); })); diff --git a/Source/Game/Handlers/GuildFinderHandler.cs b/Source/Game/Handlers/GuildFinderHandler.cs index 06b6d2f69..ebb3406d8 100644 --- a/Source/Game/Handlers/GuildFinderHandler.cs +++ b/Source/Game/Handlers/GuildFinderHandler.cs @@ -16,6 +16,7 @@ */ using Framework.Constants; +using Game.Cache; using Game.Entities; using Game.Guilds; using Game.Network; @@ -193,12 +194,12 @@ namespace Game recruitData.SecondsSinceCreated = (uint)(now - recruitRequestPair.Value.GetSubmitTime()); recruitData.SecondsUntilExpiration = (uint)(recruitRequestPair.Value.GetExpiryTime() - now); - CharacterInfo charInfo = Global.WorldMgr.GetCharacterInfo(recruitRequestPair.Key); + CharacterCacheEntry charInfo = Global.CharacterCacheStorage.GetCharacterCacheByGuid(recruitRequestPair.Key); if (charInfo != null) { recruitData.Name = charInfo.Name; - recruitData.CharacterClass = (int)charInfo.ClassID; - recruitData.CharacterGender = (int)charInfo.Sex; + recruitData.CharacterClass = (byte)charInfo.ClassId; + recruitData.CharacterGender = (byte)charInfo.Sex; recruitData.CharacterLevel = charInfo.Level; } diff --git a/Source/Game/Handlers/LFGHandler.cs b/Source/Game/Handlers/LFGHandler.cs index ec82da38c..b6d01526d 100644 --- a/Source/Game/Handlers/LFGHandler.cs +++ b/Source/Game/Handlers/LFGHandler.cs @@ -321,7 +321,7 @@ namespace Game { // Leader info MUST be sent 1st :S byte roles = (byte)roleCheck.roles.Find(roleCheck.leader).Value; - lfgRoleCheckUpdate.Members.Add(new LFGRoleCheckUpdateMember(roleCheck.leader, roles, Global.WorldMgr.GetCharacterInfo(roleCheck.leader).Level, roles > 0)); + lfgRoleCheckUpdate.Members.Add(new LFGRoleCheckUpdateMember(roleCheck.leader, roles, Global.CharacterCacheStorage.GetCharacterCacheByGuid(roleCheck.leader).Level, roles > 0)); foreach (var it in roleCheck.roles) { @@ -329,7 +329,7 @@ namespace Game continue; roles = (byte)it.Value; - lfgRoleCheckUpdate.Members.Add(new LFGRoleCheckUpdateMember(it.Key, roles, Global.WorldMgr.GetCharacterInfo(it.Key).Level, roles > 0)); + lfgRoleCheckUpdate.Members.Add(new LFGRoleCheckUpdateMember(it.Key, roles, Global.CharacterCacheStorage.GetCharacterCacheByGuid(it.Key).Level, roles > 0)); } } diff --git a/Source/Game/Handlers/MailHandler.cs b/Source/Game/Handlers/MailHandler.cs index e0e439922..c5b7b1bd6 100644 --- a/Source/Game/Handlers/MailHandler.cs +++ b/Source/Game/Handlers/MailHandler.cs @@ -17,6 +17,7 @@ using Framework.Constants; using Framework.Database; +using Game.Cache; using Game.DataStorage; using Game.Entities; using Game.Guilds; @@ -81,7 +82,7 @@ namespace Game ObjectGuid receiverGuid = ObjectGuid.Empty; if (ObjectManager.NormalizePlayerName(ref packet.Info.Target)) - receiverGuid = ObjectManager.GetPlayerGUIDByName(packet.Info.Target); + receiverGuid = Global.CharacterCacheStorage.GetCharacterGuidByName(packet.Info.Target); if (receiverGuid.IsEmpty()) { @@ -143,6 +144,7 @@ namespace Game byte mailsCount = 0; //do not allow to send to one player more than 100 mails byte receiverLevel = 0; uint receiverAccountId = 0; + uint receiverBnetAccountId = 0; if (receiver) { @@ -150,10 +152,17 @@ namespace Game mailsCount = (byte)receiver.GetMails().Count; receiverLevel = (byte)receiver.getLevel(); receiverAccountId = receiver.GetSession().GetAccountId(); + receiverBnetAccountId = receiver.GetSession().GetBattlenetAccountId(); } else { - receiverTeam = ObjectManager.GetPlayerTeamByGUID(receiverGuid); + CharacterCacheEntry characterInfo = Global.CharacterCacheStorage.GetCharacterCacheByGuid(receiverGuid); + if (characterInfo != null) + { + receiverTeam = Player.TeamForRace(characterInfo.RaceId); + receiverLevel = characterInfo.Level; + receiverAccountId = characterInfo.AccountId; + } PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_MAIL_COUNT); stmt.AddValue(0, receiverGuid.GetCounter()); @@ -162,14 +171,7 @@ namespace Game if (!result.IsEmpty()) mailsCount = (byte)result.Read(0); - stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHAR_LEVEL); - stmt.AddValue(0, receiverGuid.GetCounter()); - - result = DB.Characters.Query(stmt); - if (!result.IsEmpty()) - receiverLevel = result.Read(0); - - receiverAccountId = ObjectManager.GetPlayerAccountIdByGUID(receiverGuid); + receiverBnetAccountId = Global.BNetAccountMgr.GetIdByGameAccount(receiverAccountId); } // do not allow to have more than 100 mails in mailbox.. mails count is in opcode byte!!! - so max can be 255.. @@ -233,8 +235,11 @@ namespace Game if (item.IsBoundAccountWide() && item.IsSoulBound() && player.GetSession().GetAccountId() != receiverAccountId) { - player.SendMailResult(0, MailResponseType.Send, MailResponseResult.EquipError, InventoryResult.NotSameAccount); - return; + if (!item.IsBattlenetAccountBound() || player.GetSession().GetBattlenetAccountId() == 0 || player.GetSession().GetBattlenetAccountId() != receiverBnetAccountId) + { + player.SendMailResult(0, MailResponseType.Send, MailResponseResult.EquipError, InventoryResult.NotSameAccount); + return; + } } if (item.GetTemplate().GetFlags().HasAnyFlag(ItemFlags.Conjured) || item.m_itemData.Expiration != 0) @@ -476,16 +481,16 @@ namespace Game else { // can be calculated early - sender_accId = ObjectManager.GetPlayerAccountIdByGUID(sender_guid); + sender_accId = Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(sender_guid); - if (!ObjectManager.GetPlayerNameByGUID(sender_guid, out sender_name)) + if (!Global.CharacterCacheStorage.GetCharacterNameByGuid(sender_guid, out sender_name)) sender_name = Global.ObjectMgr.GetCypherString(CypherStrings.Unknown); } Log.outCommand(GetAccountId(), "GM {0} (Account: {1}) receiver mail item: {2} (Entry: {3} Count: {4}) and send COD money: {5} to player: {6} (Account: {7})", GetPlayerName(), GetAccountId(), it.GetTemplate().GetName(), it.GetEntry(), it.GetCount(), m.COD, sender_name, sender_accId); } else if (!receiver) - sender_accId = ObjectManager.GetPlayerAccountIdByGUID(sender_guid); + sender_accId = Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(sender_guid); // check player existence if (receiver || sender_accId != 0) diff --git a/Source/Game/Handlers/NPCHandler.cs b/Source/Game/Handlers/NPCHandler.cs index 1479ba434..b6a5093f6 100644 --- a/Source/Game/Handlers/NPCHandler.cs +++ b/Source/Game/Handlers/NPCHandler.cs @@ -289,13 +289,7 @@ namespace Game if (corpseGrave != ghostGrave) GetPlayer().TeleportTo(corpseGrave.MapID, corpseGrave.Loc.X, corpseGrave.Loc.Y, corpseGrave.Loc.Z, GetPlayer().GetOrientation()); - // or update at original position - else - GetPlayer().UpdateObjectVisibility(); } - // or update at original position - else - GetPlayer().UpdateObjectVisibility(); } [WorldPacketHandler(ClientOpcodes.BinderActivate)] diff --git a/Source/Game/Handlers/PetitionsHandler.cs b/Source/Game/Handlers/PetitionsHandler.cs index d8eaa72c2..2042a0a07 100644 --- a/Source/Game/Handlers/PetitionsHandler.cs +++ b/Source/Game/Handlers/PetitionsHandler.cs @@ -142,7 +142,7 @@ namespace Game ServerPetitionShowSignatures signaturesPacket = new ServerPetitionShowSignatures(); signaturesPacket.Item = packet.Item; signaturesPacket.Owner = GetPlayer().GetGUID(); - signaturesPacket.OwnerAccountID = ObjectGuid.Create(HighGuid.WowAccount, ObjectManager.GetPlayerAccountIdByGUID(GetPlayer().GetGUID())); + signaturesPacket.OwnerAccountID = ObjectGuid.Create(HighGuid.WowAccount, Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(GetPlayer().GetGUID())); signaturesPacket.PetitionID = (int)packet.Item.GetCounter(); // @todo verify that... do @@ -253,7 +253,7 @@ namespace Game return; // not let enemies sign guild charter - if (!WorldConfig.GetBoolValue(WorldCfg.AllowTwoSideInteractionGuild) && GetPlayer().GetTeam() != ObjectManager.GetPlayerTeamByGUID(ownerGuid)) + if (!WorldConfig.GetBoolValue(WorldCfg.AllowTwoSideInteractionGuild) && GetPlayer().GetTeam() != Global.CharacterCacheStorage.GetCharacterTeamByGuid(ownerGuid)) { Guild.SendCommandResult(this, GuildCommandType.CreateGuild, GuildCommandError.NotAllied); return; diff --git a/Source/Game/Handlers/SocialHandler.cs b/Source/Game/Handlers/SocialHandler.cs index a87ba4587..13816e6bb 100644 --- a/Source/Game/Handlers/SocialHandler.cs +++ b/Source/Game/Handlers/SocialHandler.cs @@ -17,9 +17,9 @@ using Framework.Constants; using Framework.Database; +using Game.Cache; using Game.DataStorage; using Game.Entities; -using Game.Guilds; using Game.Network; using Game.Network.Packets; using System; @@ -220,28 +220,15 @@ namespace Game if (!ObjectManager.NormalizePlayerName(ref packet.Name)) return; - PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_GUID_RACE_ACC_BY_NAME); - stmt.AddValue(0, packet.Name); - - _queryProcessor.AddQuery(DB.Characters.AsyncQuery(stmt).WithCallback(HandleAddFriendCallBack, packet.Notes)); - } - - void HandleAddFriendCallBack(string friendNote, SQLResult result) - { - if (!GetPlayer()) - return; - - ObjectGuid friendGuid = ObjectGuid.Empty; FriendsResult friendResult = FriendsResult.NotFound; - - if (!result.IsEmpty()) + ObjectGuid friendGuid = Global.CharacterCacheStorage.GetCharacterGuidByName(packet.Name); + if (!friendGuid.IsEmpty()) { - ulong lowGuid = result.Read(0); - if (lowGuid != 0) + CharacterCacheEntry characterInfo = Global.CharacterCacheStorage.GetCharacterCacheByGuid(friendGuid); + if (characterInfo != null) { - friendGuid = ObjectGuid.Create(HighGuid.Player, lowGuid); - Team team = Player.TeamForRace((Race)result.Read(1)); - uint friendAccountId = result.Read(2); + Team team = Player.TeamForRace(characterInfo.RaceId); + uint friendAccountId = characterInfo.AccountId; if (HasPermission(RBACPermissions.AllowGmFriend) || Global.AccountMgr.IsPlayerAccount(Global.AccountMgr.GetSecurity(friendAccountId, (int)Global.WorldMgr.GetRealm().Id.Realm))) { @@ -260,7 +247,7 @@ namespace Game friendResult = FriendsResult.AddedOffline; if (GetPlayer().GetSocial().AddToSocialList(friendGuid, SocialFlag.Friend)) - GetPlayer().GetSocial().SetFriendNote(friendGuid, friendNote); + GetPlayer().GetSocial().SetFriendNote(friendGuid, packet.Notes); else friendResult = FriendsResult.ListFull; } @@ -286,39 +273,21 @@ namespace Game if (!ObjectManager.NormalizePlayerName(ref packet.Name)) return; - PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_GUID_BY_NAME); - stmt.AddValue(0, packet.Name); - - _queryProcessor.AddQuery(DB.Characters.AsyncQuery(stmt).WithCallback(HandleAddIgnoreCallBack)); - } - - void HandleAddIgnoreCallBack(SQLResult result) - { - if (!GetPlayer()) - return; - - ObjectGuid IgnoreGuid = ObjectGuid.Empty; + ObjectGuid IgnoreGuid = Global.CharacterCacheStorage.GetCharacterGuidByName(packet.Name); FriendsResult ignoreResult = FriendsResult.IgnoreNotFound; - - if (result.IsEmpty()) + if (IgnoreGuid.IsEmpty()) { - ulong lowGuid = result.Read(0); - if (lowGuid != 0) + if (IgnoreGuid == GetPlayer().GetGUID()) //not add yourself + ignoreResult = FriendsResult.IgnoreSelf; + else if (GetPlayer().GetSocial().HasIgnore(IgnoreGuid)) + ignoreResult = FriendsResult.IgnoreAlready; + else { - IgnoreGuid = ObjectGuid.Create(HighGuid.Player, lowGuid); + ignoreResult = FriendsResult.IgnoreAdded; - if (IgnoreGuid == GetPlayer().GetGUID()) //not add yourself - ignoreResult = FriendsResult.IgnoreSelf; - else if (GetPlayer().GetSocial().HasIgnore(IgnoreGuid)) - ignoreResult = FriendsResult.IgnoreAlready; - else - { - ignoreResult = FriendsResult.IgnoreAdded; - - // ignore list full - if (!GetPlayer().GetSocial().AddToSocialList(IgnoreGuid, SocialFlag.Ignored)) - ignoreResult = FriendsResult.IgnoreFull; - } + // ignore list full + if (!GetPlayer().GetSocial().AddToSocialList(IgnoreGuid, SocialFlag.Ignored)) + ignoreResult = FriendsResult.IgnoreFull; } } diff --git a/Source/Game/Handlers/SpellHandler.cs b/Source/Game/Handlers/SpellHandler.cs index 6f351fd04..2350e349f 100644 --- a/Source/Game/Handlers/SpellHandler.cs +++ b/Source/Game/Handlers/SpellHandler.cs @@ -134,6 +134,13 @@ namespace Game if (player.m_unitMovedByMe != player) return; + // additional check, client outputs message on its own + if (!player.IsAlive()) + { + player.SendEquipError(InventoryResult.PlayerDead); + return; + } + Item item = player.GetItemByPos(packet.Slot, packet.PackSlot); if (!item) { @@ -181,33 +188,51 @@ namespace Game { PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHARACTER_GIFT_BY_ITEM); stmt.AddValue(0, item.GetGUID().GetCounter()); - SQLResult result = DB.Characters.Query(stmt); - - if (!result.IsEmpty()) - { - uint entry = result.Read(0); - uint flags = result.Read(1); - - item.SetGiftCreator(ObjectGuid.Empty); - item.SetEntry(entry); - item.SetItemFlags((ItemFieldFlags)flags); - item.SetState(ItemUpdateState.Changed, player); - } - else - { - Log.outError(LogFilter.Network, "Wrapped item {0} don't have record in character_gifts table and will deleted", item.GetGUID().ToString()); - player.DestroyItem(item.GetBagSlot(), item.GetSlot(), true); - return; - } - - stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_GIFT); - stmt.AddValue(0, item.GetGUID().GetCounter()); - DB.Characters.Execute(stmt); + _queryProcessor.AddQuery(DB.Characters.AsyncQuery(stmt) + .WithCallback(result => HandleOpenWrappedItemCallback(item.GetPos(), item.GetGUID(), result))); } else player.SendLoot(item.GetGUID(), LootType.Corpse); } + void HandleOpenWrappedItemCallback(ushort pos, ObjectGuid itemGuid, SQLResult result) + { + if (!GetPlayer()) + return; + + Item item = GetPlayer().GetItemByPos(pos); + if (!item) + return; + + if (item.GetGUID() != itemGuid || !item.HasItemFlag(ItemFieldFlags.Wrapped)) // during getting result, gift was swapped with another item + return; + + if (result.IsEmpty()) + { + Log.outError(LogFilter.Network, $"Wrapped item {item.GetGUID().ToString()} don't have record in character_gifts table and will deleted"); + GetPlayer().DestroyItem(item.GetBagSlot(), item.GetSlot(), true); + return; + } + + SQLTransaction trans = new SQLTransaction(); + + uint entry = result.Read(0); + uint flags = result.Read(1); + + item.SetGiftCreator(ObjectGuid.Empty); + item.SetEntry(entry); + item.SetItemFlags((ItemFieldFlags)flags); + item.SetState(ItemUpdateState.Changed, GetPlayer()); + + GetPlayer().SaveInventoryAndGoldToDB(trans); + + PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_GIFT); + stmt.AddValue(0, itemGuid.GetCounter()); + trans.Append(stmt); + + DB.Characters.CommitTransaction(trans); + } + [WorldPacketHandler(ClientOpcodes.GameObjUse)] void HandleGameObjectUse(GameObjUse packet) { diff --git a/Source/Game/Mails/MailDraft.cs b/Source/Game/Mails/MailDraft.cs index 9ee784a6a..640177ee9 100644 --- a/Source/Game/Mails/MailDraft.cs +++ b/Source/Game/Mails/MailDraft.cs @@ -99,7 +99,7 @@ namespace Game.Mails uint rc_account = 0; if (receiver == null) - rc_account = ObjectManager.GetPlayerAccountIdByGUID(receiverGuid); + rc_account = Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(receiverGuid); if (receiver == null && rc_account == 0) // sender not exist { diff --git a/Source/Game/Maps/Map.cs b/Source/Game/Maps/Map.cs index b0c6da38b..56e8cddfe 100644 --- a/Source/Game/Maps/Map.cs +++ b/Source/Game/Maps/Map.cs @@ -818,10 +818,15 @@ namespace Game.Maps { Global.ScriptMgr.OnPlayerLeaveMap(this, player); + player.getHostileRefManager().deleteReferences(); // multithreading crashfix + + bool inWorld = player.IsInWorld; player.RemoveFromWorld(); SendRemoveTransports(player); - player.UpdateObjectVisibility(true); + if (!inWorld) // if was in world, RemoveFromWorld() called DestroyForNearbyPlayers() + player.DestroyForNearbyPlayers(); // previous player->UpdateObjectVisibility(true) + Cell cell = player.GetCurrentCell(); RemoveFromGrid(player, cell); @@ -833,11 +838,14 @@ namespace Game.Maps public void RemoveFromMap(WorldObject obj, bool remove) { + bool inWorld = obj.IsInWorld && obj.GetTypeId() >= TypeId.Unit && obj.GetTypeId() <= TypeId.GameObject; obj.RemoveFromWorld(); if (obj.isActiveObject()) RemoveFromActive(obj); - obj.UpdateObjectVisibility(true); + if (!inWorld) // if was in world, RemoveFromWorld() called DestroyForNearbyPlayers() + obj.DestroyForNearbyPlayers(); // previous obj->UpdateObjectVisibility(true) + Cell cell = obj.GetCurrentCell(); RemoveFromGrid(obj, cell); diff --git a/Source/Game/Network/Packets/QueryPackets.cs b/Source/Game/Network/Packets/QueryPackets.cs index 5c601ace4..ae7e98415 100644 --- a/Source/Game/Network/Packets/QueryPackets.cs +++ b/Source/Game/Network/Packets/QueryPackets.cs @@ -20,6 +20,7 @@ using Framework.Constants; using Framework.Dynamic; using Framework.GameMath; using Framework.IO; +using Game.Cache; using Game.Entities; using System; using System.Collections.Generic; @@ -624,7 +625,7 @@ namespace Game.Network.Packets { public bool Initialize(ObjectGuid guid, Player player = null) { - CharacterInfo characterInfo = Global.WorldMgr.GetCharacterInfo(guid); + CharacterCacheEntry characterInfo = Global.CharacterCacheStorage.GetCharacterCacheByGuid(guid); if (characterInfo == null) return false; @@ -646,15 +647,15 @@ namespace Game.Network.Packets } else { - uint accountId = ObjectManager.GetPlayerAccountIdByGUID(guid); + uint accountId = Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(guid); uint bnetAccountId = Global.BNetAccountMgr.GetIdByGameAccount(accountId); AccountID = ObjectGuid.Create(HighGuid.WowAccount, accountId); BnetAccountID = ObjectGuid.Create(HighGuid.BNetAccount, bnetAccountId); Name = characterInfo.Name; - RaceID = characterInfo.RaceID; + RaceID = characterInfo.RaceId; Sex = characterInfo.Sex; - ClassID = characterInfo.ClassID; + ClassID = characterInfo.ClassId; Level = characterInfo.Level; } diff --git a/Source/Game/Quest/Quest.cs b/Source/Game/Quest/Quest.cs index be972b94f..7e759b0b8 100644 --- a/Source/Game/Quest/Quest.cs +++ b/Source/Game/Quest/Quest.cs @@ -427,6 +427,9 @@ namespace Game public uint GetRewItemsCount() { return _rewItemsCount; } public uint GetRewCurrencyCount() { return _rewCurrencyCount; } + public void SetEventIdForQuest(ushort eventId) { _eventIdForQuest = eventId; } + public ushort GetEventIdForQuest() { return _eventIdForQuest; } + #region Fields public uint Id; public QuestType Type; @@ -542,6 +545,7 @@ namespace Game uint _rewChoiceItemsCount; uint _rewItemsCount; uint _rewCurrencyCount; + ushort _eventIdForQuest; #endregion } diff --git a/Source/Game/Scripting/CoreScripts.cs b/Source/Game/Scripting/CoreScripts.cs index 0714c20be..e8af146fe 100644 --- a/Source/Game/Scripting/CoreScripts.cs +++ b/Source/Game/Scripting/CoreScripts.cs @@ -646,7 +646,10 @@ namespace Game.Scripting public virtual void OnCreate(Player player) { } // Called when a player is deleted. - public virtual void OnDelete(ObjectGuid guid) { } + public virtual void OnDelete(ObjectGuid guid, uint accountId) { } + + // Called when a player delete failed + public virtual void OnFailedDelete(ObjectGuid guid, uint accountId) { } // Called when a player is about to be saved. public virtual void OnSave(Player player) { } diff --git a/Source/Game/Scripting/ScriptManager.cs b/Source/Game/Scripting/ScriptManager.cs index 5667f9c0c..c46ae9b7e 100644 --- a/Source/Game/Scripting/ScriptManager.cs +++ b/Source/Game/Scripting/ScriptManager.cs @@ -1182,9 +1182,13 @@ namespace Game.Scripting { ForEach(p => p.OnCreate(player)); } - public void OnPlayerDelete(ObjectGuid guid) + public void OnPlayerDelete(ObjectGuid guid, uint accountId) { - ForEach(p => p.OnDelete(guid)); + ForEach(p => p.OnDelete(guid, accountId)); + } + public void OnPlayerFailedDelete(ObjectGuid guid, uint accountId) + { + ForEach(p => p.OnFailedDelete(guid, accountId)); } public void OnPlayerSave(Player player) { diff --git a/Source/Game/Server/WorldManager.cs b/Source/Game/Server/WorldManager.cs index 58d1834ff..38b944de8 100644 --- a/Source/Game/Server/WorldManager.cs +++ b/Source/Game/Server/WorldManager.cs @@ -704,6 +704,10 @@ namespace Game Global.BlackMarketMgr.LoadAuctions(); } + // Load before guilds and arena teams + Log.outInfo(LogFilter.ServerLoading, "Loading character cache store..."); + Global.CharacterCacheStorage.LoadCharacterCacheStorage(); + Log.outInfo(LogFilter.ServerLoading, "Loading Guild rewards..."); Global.GuildMgr.LoadGuildRewards(); @@ -935,8 +939,6 @@ namespace Game Log.outInfo(LogFilter.ServerLoading, "Calculate next currency reset time..."); InitCurrencyResetTime(); - LoadCharacterInfoStorage(); - Log.outInfo(LogFilter.ServerLoading, "Loading race and class expansion requirements..."); Global.ObjectMgr.LoadRaceAndClassExpansionRequirements(); @@ -1564,14 +1566,7 @@ namespace Game if (mode == BanMode.Account) account = Global.AccountMgr.GetId(nameOrIP); else if (mode == BanMode.Character) - { - stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_ACCOUNT_BY_NAME); - stmt.AddValue(0, nameOrIP); - - SQLResult result = DB.Characters.Query(stmt); - if (!result.IsEmpty()) - account = result.Read(0); - } + account = Global.CharacterCacheStorage.GetCharacterAccountIdByName(nameOrIP); if (account == 0) return false; @@ -1595,7 +1590,7 @@ namespace Game // Pick a player to ban if not online if (!pBanned) { - guid = ObjectManager.GetPlayerGUIDByName(name); + guid = Global.CharacterCacheStorage.GetCharacterGuidByName(name); if (guid.IsEmpty()) return BanReturn.Notfound; // Nobody to ban } @@ -1633,7 +1628,7 @@ namespace Game // Pick a player to ban if not online if (!pBanned) { - guid = ObjectManager.GetPlayerGUIDByName(name); + guid = Global.CharacterCacheStorage.GetCharacterGuidByName(name); if (guid.IsEmpty()) return false; // Nobody to ban } @@ -2180,93 +2175,6 @@ namespace Game _queryProcessor.ProcessReadyQueries(); } - public CharacterInfo GetCharacterInfo(ObjectGuid guid) { return _characterInfoStorage.LookupByKey(guid); } - - public void LoadCharacterInfoStorage() - { - Log.outInfo(LogFilter.ServerLoading, "Loading character name data"); - - _characterInfoStorage.Clear(); - - SQLResult result = DB.Characters.Query("SELECT guid, name, account, race, gender, class, level, deleteDate FROM characters"); - if (result.IsEmpty()) - { - Log.outInfo(LogFilter.ServerLoading, "No character name data loaded, empty query"); - return; - } - - uint count = 0; - do - { - AddCharacterInfo(ObjectGuid.Create(HighGuid.Player, result.Read(0)), result.Read(2), result.Read(1), - result.Read(4), result.Read(3), result.Read(5), result.Read(6), result.Read(7) != 0); - ++count; - } while (result.NextRow()); - - Log.outInfo(LogFilter.ServerLoading, "Loaded name data for {0} characters", count); - } - - public void AddCharacterInfo(ObjectGuid guid, uint accountId, string name, byte gender, byte race, byte playerClass, byte level, bool isDeleted) - { - CharacterInfo data = new CharacterInfo(); - data.Name = name; - data.AccountId = accountId; - data.RaceID = (Race)race; - data.Sex = (Gender)gender; - data.ClassID = (Class)playerClass; - data.Level = level; - data.IsDeleted = isDeleted; - _characterInfoStorage[guid] = data; - } - - public void DeleteCharacterInfo(ObjectGuid guid) { _characterInfoStorage.Remove(guid); } - - public void UpdateCharacterInfo(ObjectGuid guid, string name, Gender gender = Gender.None, Race race = Race.None) - { - if (!_characterInfoStorage.ContainsKey(guid)) - return; - - var charData = _characterInfoStorage[guid]; - charData.Name = name; - - if (gender != Gender.None) - charData.Sex = gender; - - if (race != Race.None) - charData.RaceID = race; - - InvalidatePlayer data = new InvalidatePlayer(); - data.Guid = guid; - SendGlobalMessage(data); - } - - public void UpdateCharacterInfoLevel(ObjectGuid guid, byte level) - { - if (!_characterInfoStorage.ContainsKey(guid)) - return; - - _characterInfoStorage[guid].Level = level; - } - - public void UpdateCharacterInfoAccount(ObjectGuid guid, uint accountId) - { - if (!_characterInfoStorage.ContainsKey(guid)) - return; - - _characterInfoStorage[guid].AccountId = accountId; - } - - public void UpdateCharacterInfoDeleted(ObjectGuid guid, bool deleted, string name = null) - { - if (!_characterInfoStorage.ContainsKey(guid)) - return; - - _characterInfoStorage[guid].IsDeleted = deleted; - - if (!string.IsNullOrEmpty(name)) - _characterInfoStorage[guid].Name = name; - } - public void ReloadRBAC() { // Passive reload, we mark the data as invalidated and next time a permission is checked it will be reloaded @@ -2275,8 +2183,6 @@ namespace Game session.InvalidateRBACData(); } - public bool HasCharacterInfo(ObjectGuid guid) { return _characterInfoStorage.ContainsKey(guid); } - public List GetAllSessions() { return m_sessions.Values.ToList(); @@ -2409,8 +2315,6 @@ namespace Game Dictionary m_Autobroadcasts = new Dictionary(); - Dictionary _characterInfoStorage = new Dictionary(); - CleaningFlags m_CleaningFlags; float m_MaxVisibleDistanceOnContinents = SharedConst.DefaultVisibilityDistance; @@ -2519,17 +2423,6 @@ namespace Game Restart = 2, } - public class CharacterInfo - { - public string Name; - public uint AccountId; - public Class ClassID; - public Race RaceID; - public Gender Sex; - public byte Level; - public bool IsDeleted; - } - public class WorldWorldTextBuilder : MessageBuilder { public WorldWorldTextBuilder(uint textId, params object[] args) diff --git a/Source/Game/Server/WorldSession.cs b/Source/Game/Server/WorldSession.cs index 0a28e86de..63337286c 100644 --- a/Source/Game/Server/WorldSession.cs +++ b/Source/Game/Server/WorldSession.cs @@ -428,28 +428,28 @@ namespace Game public void LoadTutorialsData(SQLResult result) { if (!result.IsEmpty()) + { for (var i = 0; i < SharedConst.MaxAccountTutorialValues; i++) tutorials[i] = result.Read(i); + tutorialsChanged |= TutorialsFlag.LoadedFromDB; + } - tutorialsChanged = false; + tutorialsChanged &= ~TutorialsFlag.Changed; } public void SaveTutorialsData(SQLTransaction trans) { - if (!tutorialsChanged) + if (!tutorialsChanged.HasAnyFlag(TutorialsFlag.Changed)) return; - PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_HAS_TUTORIALS); - stmt.AddValue(0, GetAccountId()); - bool hasTutorials = !DB.Characters.Query(stmt).IsEmpty(); - // Modify data in DB - stmt = DB.Characters.GetPreparedStatement(hasTutorials ? CharStatements.UPD_TUTORIALS : CharStatements.INS_TUTORIALS); + bool hasTutorialsInDB = tutorialsChanged.HasAnyFlag(TutorialsFlag.LoadedFromDB); + PreparedStatement stmt = DB.Characters.GetPreparedStatement(hasTutorialsInDB ? CharStatements.UPD_TUTORIALS : CharStatements.INS_TUTORIALS); for (var i = 0; i < SharedConst.MaxAccountTutorialValues; ++i) stmt.AddValue(i, tutorials[i]); stmt.AddValue(SharedConst.MaxAccountTutorialValues, GetAccountId()); trans.Append(stmt); - tutorialsChanged = false; + tutorialsChanged &= ~TutorialsFlag.Changed; } public void SendConnectToInstance(ConnectToSerial serial) @@ -622,6 +622,8 @@ namespace Game public ulong GetConnectToInstanceKey() { return _instanceConnectKey.Raw; } + public QueryCallbackProcessor GetQueryProcessor() { return _queryProcessor; } + void SetLogoutStartTime(long requestTime) { _logoutTime = requestTime; @@ -780,7 +782,7 @@ namespace Game if (tutorials[index] != value) { tutorials[index] = value; - tutorialsChanged = true; + tutorialsChanged |= TutorialsFlag.Changed; } } @@ -855,7 +857,7 @@ namespace Game uint m_clientTimeDelay; AccountData[] _accountData = new AccountData[(int)AccountDataTypes.Max]; uint[] tutorials = new uint[SharedConst.MaxAccountTutorialValues]; - bool tutorialsChanged; + TutorialsFlag tutorialsChanged; Array _realmListSecret = new Array(32); Dictionary _realmCharacterCounts = new Dictionary(); diff --git a/Source/Game/SupportSystem/SupportTickets.cs b/Source/Game/SupportSystem/SupportTickets.cs index d79c65569..f8bd356d1 100644 --- a/Source/Game/SupportSystem/SupportTickets.cs +++ b/Source/Game/SupportSystem/SupportTickets.cs @@ -79,7 +79,7 @@ namespace Game.SupportSystem { string name = ""; if (!_playerGuid.IsEmpty()) - ObjectManager.GetPlayerNameByGUID(_playerGuid, out name); + Global.CharacterCacheStorage.GetCharacterNameByGuid(_playerGuid, out name); return name; } @@ -89,7 +89,7 @@ namespace Game.SupportSystem { string name; if (!_assignedTo.IsEmpty()) - if (ObjectManager.GetPlayerNameByGUID(_assignedTo, out name)) + if (Global.CharacterCacheStorage.GetCharacterNameByGuid(_assignedTo, out name)) return name; return ""; @@ -433,9 +433,8 @@ namespace Game.SupportSystem ss.Append(handler.GetParsedString(CypherStrings.CommandTicketlistname, GetPlayerName())); ss.Append(handler.GetParsedString(CypherStrings.CommandTicketlistagecreate, Time.secsToTimeString(curTime - _createTime, true, false))); - string name; - if (ObjectManager.GetPlayerNameByGUID(_assignedTo, out name)) - ss.Append(handler.GetParsedString(CypherStrings.CommandTicketlistassignedto, name)); + if (!_assignedTo.IsEmpty()) + ss.Append(handler.GetParsedString(CypherStrings.CommandTicketlistassignedto, GetAssignedToName())); if (detailed) {