diff --git a/Source/Framework/Database/Databases/CharacterDatabase.cs b/Source/Framework/Database/Databases/CharacterDatabase.cs index 0eee63526..bfc440ba9 100644 --- a/Source/Framework/Database/Databases/CharacterDatabase.cs +++ b/Source/Framework/Database/Databases/CharacterDatabase.cs @@ -26,7 +26,7 @@ namespace Framework.Database "iit.itemModifiedAppearanceAllSpecs, iit.itemModifiedAppearanceSpec1, iit.itemModifiedAppearanceSpec2, iit.itemModifiedAppearanceSpec3, iit.itemModifiedAppearanceSpec4, " + "iit.spellItemEnchantmentAllSpecs, iit.spellItemEnchantmentSpec1, iit.spellItemEnchantmentSpec2, iit.spellItemEnchantmentSpec3, iit.spellItemEnchantmentSpec4, " + "ig.gemItemId1, ig.gemBonuses1, ig.gemContext1, ig.gemScalingLevel1, ig.gemItemId2, ig.gemBonuses2, ig.gemContext2, ig.gemScalingLevel2, ig.gemItemId3, ig.gemBonuses3, ig.gemContext3, ig.gemScalingLevel3, " + - "im.fixedScalingLevel, im.artifactKnowledgeLevel, iz.xp, iz.level, iz.knowledgeLevel"; + "im.fixedScalingLevel, im.artifactKnowledgeLevel"; PrepareStatement(CharStatements.DEL_QUEST_POOL_SAVE, "DELETE FROM pool_quest_save WHERE pool_id = ?"); PrepareStatement(CharStatements.INS_QUEST_POOL_SAVE, "INSERT INTO pool_quest_save (pool_id, quest_id) VALUES (?, ?)"); @@ -109,7 +109,7 @@ namespace Framework.Database PrepareStatement(CharStatements.DEL_RESET_CHARACTER_QUESTSTATUS_SEASONAL_BY_EVENT, "DELETE FROM character_queststatus_seasonal WHERE event = ?"); PrepareStatement(CharStatements.SEL_CHARACTER_REPUTATION, "SELECT faction, standing, flags FROM character_reputation WHERE guid = ?"); - PrepareStatement(CharStatements.SEL_CHARACTER_INVENTORY, "SELECT " + SelectItemInstanceContent + ", bag, slot FROM character_inventory ci JOIN item_instance ii ON ci.item = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid LEFT JOIN item_instance_azerite iz ON ii.guid = iz.itemGuid WHERE ci.guid = ? ORDER BY (ii.flags & 0x80000) ASC, bag ASC, slot ASC"); + PrepareStatement(CharStatements.SEL_CHARACTER_INVENTORY, "SELECT " + SelectItemInstanceContent + ", bag, slot FROM character_inventory ci JOIN item_instance ii ON ci.item = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid WHERE ci.guid = ? ORDER BY (ii.flags & 0x80000) ASC, bag ASC, slot ASC"); PrepareStatement(CharStatements.SEL_CHARACTER_ACTIONS, "SELECT a.button, a.action, a.type FROM character_action as a, characters as c WHERE a.guid = c.guid AND a.spec = c.activeTalentGroup AND a.guid = ? ORDER BY button"); PrepareStatement(CharStatements.SEL_CHARACTER_MAILCOUNT, "SELECT COUNT(id) FROM mail WHERE receiver = ? AND (checked & 1) = 0 AND deliver_time <= ?"); PrepareStatement(CharStatements.SEL_CHARACTER_MAILDATE, "SELECT MIN(deliver_time) FROM mail WHERE receiver = ? AND (checked & 1) = 0"); @@ -141,8 +141,10 @@ namespace Framework.Database PrepareStatement(CharStatements.SEL_ACCOUNT_INSTANCELOCKTIMES, "SELECT instanceId, releaseTime FROM account_instance_times WHERE accountId = ?"); PrepareStatement(CharStatements.SEL_CHARACTER_ACTIONS_SPEC, "SELECT button, action, type FROM character_action WHERE guid = ? AND spec = ? ORDER BY button"); - PrepareStatement(CharStatements.SEL_MAILITEMS, "SELECT " + SelectItemInstanceContent + ", ii.owner_guid FROM mail_items mi JOIN item_instance ii ON mi.item_guid = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid LEFT JOIN item_instance_azerite iz ON ii.guid = iz.itemGuid WHERE mail_id = ?"); - PrepareStatement(CharStatements.SEL_AUCTION_ITEMS, "SELECT " + SelectItemInstanceContent + " FROM auctionhouse ah JOIN item_instance ii ON ah.itemguid = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid LEFT JOIN item_instance_azerite iz ON ii.guid = iz.itemGuid"); + PrepareStatement(CharStatements.SEL_MAILITEMS, "SELECT " + SelectItemInstanceContent + ", ii.owner_guid, m.id FROM mail_items mi INNER JOIN mail m ON mi.mail_id = m.id LEFT JOIN item_instance ii ON mi.item_guid = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid WHERE m.receiver = ?"); + PrepareStatement(CharStatements.SEL_MAILITEMS_ARTIFACT, "SELECT a.itemGuid, a.xp, a.artifactAppearanceId, a.artifactTierId, ap.artifactPowerId, ap.purchasedRank FROM item_instance_artifact_powers ap LEFT JOIN item_instance_artifact a ON ap.itemGuid = a.itemGuid INNER JOIN mail_items mi ON a.itemGuid = mi.item_guid INNER JOIN mail m ON mi.mail_id = m.id WHERE m.receiver = ?"); + PrepareStatement(CharStatements.SEL_MAILITEMS_AZERITE, "SELECT iz.itemGuid, iz.xp, iz.level, iz.knowledgeLevel FROM item_instance_azerite iz INNER JOIN mail_items mi ON iz.itemGuid = mi.item_guid INNER JOIN mail m ON mi.mail_id = m.id WHERE m.receiver = ?"); + PrepareStatement(CharStatements.SEL_AUCTION_ITEMS, "SELECT " + SelectItemInstanceContent + " FROM auctionhouse ah JOIN item_instance ii ON ah.itemguid = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid"); PrepareStatement(CharStatements.SEL_AUCTIONS, "SELECT id, auctioneerguid, itemguid, itemEntry, count, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit FROM auctionhouse ah INNER JOIN item_instance ii ON ii.guid = ah.itemguid"); PrepareStatement(CharStatements.INS_AUCTION, "INSERT INTO auctionhouse (id, auctioneerguid, itemguid, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); PrepareStatement(CharStatements.DEL_AUCTION, "DELETE FROM auctionhouse WHERE id = ?"); @@ -186,6 +188,7 @@ namespace Framework.Database PrepareStatement(CharStatements.INS_ITEM_INSTANCE_MODIFIERS, "INSERT INTO item_instance_modifiers (itemGuid, fixedScalingLevel, artifactKnowledgeLevel) VALUES (?, ?, ?)"); PrepareStatement(CharStatements.DEL_ITEM_INSTANCE_MODIFIERS, "DELETE FROM item_instance_modifiers WHERE itemGuid = ?"); PrepareStatement(CharStatements.DEL_ITEM_INSTANCE_MODIFIERS_BY_OWNER, "DELETE im FROM item_instance_modifiers im LEFT JOIN item_instance ii ON im.itemGuid = ii.guid WHERE ii.owner_guid = ?"); + PrepareStatement(CharStatements.SEL_ITEM_INSTANCE_AZERITE, "SELECT iz.itemGuid, iz.xp, iz.level, iz.knowledgeLevel FROM item_instance_azerite iz INNER JOIN character_inventory ci ON iz.itemGuid = ci.item WHERE ci.guid = ?"); PrepareStatement(CharStatements.INS_ITEM_INSTANCE_AZERITE, "INSERT INTO item_instance_azerite (itemGuid, xp, level, knowledgeLevel) VALUES (?, ?, ?, ?)"); PrepareStatement(CharStatements.UPD_ITEM_INSTANCE_AZERITE_ON_LOAD, "UPDATE item_instance_azerite SET xp = ?, knowledgeLevel = ? WHERE itemGuid = ?"); PrepareStatement(CharStatements.DEL_ITEM_INSTANCE_AZERITE, "DELETE FROM item_instance_azerite WHERE itemGuid = ?"); @@ -221,7 +224,7 @@ namespace Framework.Database // 0: uint32, 1: uint8, 2: uint8, 3: uint32, 4: uint32 PrepareStatement(CharStatements.INS_GUILD_BANK_ITEM, "INSERT INTO guild_bank_item (guildid, TabId, SlotId, item_guid) VALUES (?, ?, ?, ?)"); PrepareStatement(CharStatements.DEL_GUILD_BANK_ITEM, "DELETE FROM guild_bank_item WHERE guildid = ? AND TabId = ? AND SlotId = ?"); // 0: uint32, 1: uint8, 2: uint8 - PrepareStatement(CharStatements.SEL_GUILD_BANK_ITEMS, "SELECT " + SelectItemInstanceContent + ", guildid, TabId, SlotId FROM guild_bank_item gbi INNER JOIN item_instance ii ON gbi.item_guid = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid LEFT JOIN item_instance_azerite iz ON ii.guid = iz.itemGuid"); + PrepareStatement(CharStatements.SEL_GUILD_BANK_ITEMS, "SELECT " + SelectItemInstanceContent + ", guildid, TabId, SlotId FROM guild_bank_item gbi INNER JOIN item_instance ii ON gbi.item_guid = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid"); PrepareStatement(CharStatements.DEL_GUILD_BANK_ITEMS, "DELETE FROM guild_bank_item WHERE guildid = ?"); // 0: uint32 // 0: uint32, 1: uint8, 2: uint8, 3: uint8, 4: uint32 PrepareStatement(CharStatements.INS_GUILD_BANK_RIGHT, "INSERT INTO guild_bank_right (guildid, TabId, rid, gbright, SlotPerDay) VALUES (?, ?, ?, ?, ?) " + @@ -499,7 +502,7 @@ 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_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.SEL_MAIL, "SELECT id, messageType, sender, receiver, subject, body, 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 = ?"); PrepareStatement(CharStatements.SEL_MAIL_COUNT_ITEM, "SELECT COUNT(itemEntry) FROM mail_items mi INNER JOIN item_instance ii ON ii.guid = mi.item_guid WHERE itemEntry = ?"); @@ -833,6 +836,8 @@ namespace Framework.Database SEL_CHARACTER_QUESTSTATUSREW, SEL_ACCOUNT_INSTANCELOCKTIMES, SEL_MAILITEMS, + SEL_MAILITEMS_ARTIFACT, + SEL_MAILITEMS_AZERITE, SEL_AUCTION_ITEMS, INS_AUCTION, DEL_AUCTION, @@ -875,6 +880,7 @@ namespace Framework.Database INS_ITEM_INSTANCE_MODIFIERS, DEL_ITEM_INSTANCE_MODIFIERS, DEL_ITEM_INSTANCE_MODIFIERS_BY_OWNER, + SEL_ITEM_INSTANCE_AZERITE, INS_ITEM_INSTANCE_AZERITE, UPD_ITEM_INSTANCE_AZERITE_ON_LOAD, DEL_ITEM_INSTANCE_AZERITE, diff --git a/Source/Game/Entities/Item/AzeriteItem.cs b/Source/Game/Entities/Item/AzeriteItem.cs index 555146a54..5b1865678 100644 --- a/Source/Game/Entities/Item/AzeriteItem.cs +++ b/Source/Game/Entities/Item/AzeriteItem.cs @@ -66,60 +66,51 @@ namespace Game.Entities trans.Append(stmt); } - public override bool LoadFromDB(ulong guid, ObjectGuid ownerGuid, SQLFields fields, uint entry) + public void LoadAzeriteItemData(AzeriteData azeriteData) { - if (!base.LoadFromDB(guid, ownerGuid, fields, entry)) - return false; - bool needSave = false; - ulong xp = fields.Read(43); - uint level = fields.Read(44); - uint knowledgeLevel = fields.Read(45); - - if (!CliDB.AzeriteLevelInfoStorage.ContainsKey(level)) + if (!CliDB.AzeriteLevelInfoStorage.ContainsKey(azeriteData.Level)) { - xp = 0; - level = 1; - knowledgeLevel = GetCurrentKnowledgeLevel(); + azeriteData.Xp = 0; + azeriteData.Level = 1; + azeriteData.KnowledgeLevel = GetCurrentKnowledgeLevel(); needSave = true; } - else if (level > PlayerConst.MaxAzeriteItemLevel) + else if (azeriteData.Level > PlayerConst.MaxAzeriteItemLevel) { - xp = 0; - level = PlayerConst.MaxAzeriteItemLevel; + azeriteData.Xp = 0; + azeriteData.Level = PlayerConst.MaxAzeriteItemLevel; needSave = true; } - if (knowledgeLevel != GetCurrentKnowledgeLevel()) + if (azeriteData.KnowledgeLevel != GetCurrentKnowledgeLevel()) { // rescale XP to maintain same progress % - ulong oldMax = CalcTotalXPToNextLevel(level, knowledgeLevel); - knowledgeLevel = GetCurrentKnowledgeLevel(); - ulong newMax = CalcTotalXPToNextLevel(level, knowledgeLevel); - xp = (ulong)(xp / (double)oldMax * newMax); + ulong oldMax = CalcTotalXPToNextLevel(azeriteData.Level, azeriteData.KnowledgeLevel); + azeriteData.KnowledgeLevel = GetCurrentKnowledgeLevel(); + ulong newMax = CalcTotalXPToNextLevel(azeriteData.Level, azeriteData.KnowledgeLevel); + azeriteData.Xp = (ulong)(azeriteData.Xp / (double)oldMax * newMax); needSave = true; } - else if (knowledgeLevel > PlayerConst.MaxAzeriteItemKnowledgeLevel) + else if (azeriteData.KnowledgeLevel > PlayerConst.MaxAzeriteItemKnowledgeLevel) { - knowledgeLevel = PlayerConst.MaxAzeriteItemKnowledgeLevel; + azeriteData.KnowledgeLevel = PlayerConst.MaxAzeriteItemKnowledgeLevel; needSave = true; } - SetUpdateFieldValue(m_values.ModifyValue(m_azeriteItemData).ModifyValue(m_azeriteItemData.Xp), xp); - SetUpdateFieldValue(m_values.ModifyValue(m_azeriteItemData).ModifyValue(m_azeriteItemData.Level), level); - SetUpdateFieldValue(m_values.ModifyValue(m_azeriteItemData).ModifyValue(m_azeriteItemData.KnowledgeLevel), knowledgeLevel); + SetUpdateFieldValue(m_values.ModifyValue(m_azeriteItemData).ModifyValue(m_azeriteItemData.Xp), azeriteData.Xp); + SetUpdateFieldValue(m_values.ModifyValue(m_azeriteItemData).ModifyValue(m_azeriteItemData.Level), azeriteData.Level); + SetUpdateFieldValue(m_values.ModifyValue(m_azeriteItemData).ModifyValue(m_azeriteItemData.KnowledgeLevel), azeriteData.KnowledgeLevel); if (needSave) { PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_ITEM_INSTANCE_AZERITE_ON_LOAD); - stmt.AddValue(0, xp); - stmt.AddValue(1, knowledgeLevel); - stmt.AddValue(2, guid); + stmt.AddValue(0, azeriteData.Xp); + stmt.AddValue(1, azeriteData.KnowledgeLevel); + stmt.AddValue(2, GetGUID().GetCounter()); DB.Characters.Execute(stmt); } - - return true; } public override void DeleteFromDB(SQLTransaction trans) @@ -136,6 +127,16 @@ namespace Game.Entities return CliDB.AzeriteLevelInfoStorage.LookupByKey(m_azeriteItemData.Level).ItemLevel; } + uint GetLevel() { return m_azeriteItemData.Level; } + uint GetEffectiveLevel() + { + uint level = m_azeriteItemData.AuraLevel; + if (level == 0) + level = m_azeriteItemData.Level; + + return level; + } + uint GetCurrentKnowledgeLevel() { // count weeks from 26.06.2019 @@ -277,4 +278,11 @@ namespace Game.Entities base.ClearUpdateMask(remove); } } + + public class AzeriteData + { + public ulong Xp; + public uint Level; + public uint KnowledgeLevel; + } } diff --git a/Source/Game/Entities/Item/Item.cs b/Source/Game/Entities/Item/Item.cs index 314bf5597..754336aba 100644 --- a/Source/Game/Entities/Item/Item.cs +++ b/Source/Game/Entities/Item/Item.cs @@ -525,7 +525,7 @@ namespace Game.Entities return true; } - public void LoadArtifactData(Player owner, ulong xp, uint artifactAppearanceId, uint artifactTier, List powers) + public void LoadArtifactData(Player owner, ulong xp, uint artifactAppearanceId, uint artifactTier, List powers) { for (byte i = 0; i <= artifactTier; ++i) InitArtifactPowers(GetTemplate().GetArtifactID(), i); @@ -539,7 +539,7 @@ namespace Game.Entities SetAppearanceModId(artifactAppearance.ItemAppearanceModifierID); byte totalPurchasedRanks = 0; - foreach (ArtifactPowerLoadInfo power in powers) + foreach (ArtifactPowerData power in powers) { power.CurrentRankWithBonus += power.PurchasedRank; totalPurchasedRanks += power.PurchasedRank; @@ -585,7 +585,7 @@ namespace Game.Entities SetArtifactPower((ushort)power.ArtifactPowerId, power.PurchasedRank, power.CurrentRankWithBonus); } - foreach (ArtifactPowerLoadInfo power in powers) + foreach (ArtifactPowerData power in powers) { ArtifactPowerRecord scaledArtifactPowerEntry = CliDB.ArtifactPowerStorage.LookupByKey(power.ArtifactPowerId); if (!scaledArtifactPowerEntry.Flags.HasAnyFlag(ArtifactPowerFlag.ScalesWithNumPowers)) @@ -2149,7 +2149,7 @@ namespace Game.Entities return null; } - void AddArtifactPower(ArtifactPowerLoadInfo artifactPower) + void AddArtifactPower(ArtifactPowerData artifactPower) { int index = m_artifactPowerIdToIndex.Count; m_artifactPowerIdToIndex[artifactPower.ArtifactPowerId] = (ushort)index; @@ -2183,7 +2183,7 @@ namespace Game.Entities if (m_artifactPowerIdToIndex.ContainsKey(artifactPower.Id)) continue; - ArtifactPowerLoadInfo powerData = new ArtifactPowerLoadInfo(); + ArtifactPowerData powerData = new ArtifactPowerData(); powerData.ArtifactPowerId = artifactPower.Id; powerData.PurchasedRank = 0; powerData.CurrentRankWithBonus = (byte)((artifactPower.Flags & ArtifactPowerFlag.First) == ArtifactPowerFlag.First ? 1 : 0); @@ -2945,13 +2945,88 @@ namespace Game.Entities } } - public class ArtifactPowerLoadInfo + public class ArtifactPowerData { public uint ArtifactPowerId; public byte PurchasedRank; public byte CurrentRankWithBonus; } + class ArtifactData + { + public ulong Xp; + public uint ArtifactAppearanceId; + public uint ArtifactTierId; + public List ArtifactPowers = new List(); + } + + class ItemAdditionalLoadInfo + { + public ArtifactData Artifact; + public AzeriteData AzeriteItem; + + public static void Init(Dictionary loadInfo, SQLResult artifactResult, SQLResult azeriteItemResult) + { + // 0 1 2 3 4 5 + // SELECT a.itemGuid, a.xp, a.artifactAppearanceId, a.artifactTierId, ap.artifactPowerId, ap.purchasedRank FROM item_instance_artifact_powers ap LEFT JOIN item_instance_artifact a ON ap.itemGuid = a.itemGuid ... + if (!artifactResult.IsEmpty()) + { + do + { + ItemAdditionalLoadInfo info = new ItemAdditionalLoadInfo(); + if (info.Artifact == null) + info.Artifact = new ArtifactData(); + + info.Artifact.Xp = artifactResult.Read(1); + info.Artifact.ArtifactAppearanceId = artifactResult.Read(2); + info.Artifact.ArtifactTierId = artifactResult.Read(3); + + ArtifactPowerData artifactPowerData = new ArtifactPowerData(); + artifactPowerData.ArtifactPowerId = artifactResult.Read(4); + artifactPowerData.PurchasedRank = artifactResult.Read(5); + + ArtifactPowerRecord artifactPower = CliDB.ArtifactPowerStorage.LookupByKey(artifactPowerData.ArtifactPowerId); + if (artifactPower != null) + { + uint maxRank = artifactPower.MaxPurchasableRank; + // allow ARTIFACT_POWER_FLAG_FINAL to overflow maxrank here - needs to be handled in Item::CheckArtifactUnlock (will refund artifact power) + if (artifactPower.Flags.HasAnyFlag(ArtifactPowerFlag.MaxRankWithTier) && artifactPower.Tier < info.Artifact.ArtifactTierId) + maxRank += info.Artifact.ArtifactTierId - artifactPower.Tier; + + if (artifactPowerData.PurchasedRank > maxRank) + artifactPowerData.PurchasedRank = (byte)maxRank; + + artifactPowerData.CurrentRankWithBonus = (byte)((artifactPower.Flags & ArtifactPowerFlag.First) == ArtifactPowerFlag.First ? 1 : 0); + + info.Artifact.ArtifactPowers.Add(artifactPowerData); + } + + loadInfo[artifactResult.Read(0)] = info; + + } while (artifactResult.NextRow()); + } + + // 0 1 2 3 + // SELECT iz.itemGuid, iz.xp, iz.level, iz.knowledgeLevel FROM item_instance_azerite iz INNER JOIN ... + if (!azeriteItemResult.IsEmpty()) + { + do + { + ItemAdditionalLoadInfo info = new ItemAdditionalLoadInfo(); + if (info.AzeriteItem == null) + info.AzeriteItem = new AzeriteData(); + + info.AzeriteItem.Xp = azeriteItemResult.Read(1); + info.AzeriteItem.Level = azeriteItemResult.Read(2); + info.AzeriteItem.KnowledgeLevel = azeriteItemResult.Read(3); + + loadInfo[azeriteItemResult.Read(0)] = info; + + } while (azeriteItemResult.NextRow()); + } + } + } + [StructLayout(LayoutKind.Sequential)] public class ItemDynamicFieldGems { diff --git a/Source/Game/Entities/Player/Player.DB.cs b/Source/Game/Entities/Player/Player.DB.cs index aa6b1c183..c99b041e9 100644 --- a/Source/Game/Entities/Player/Player.DB.cs +++ b/Source/Game/Entities/Player/Player.DB.cs @@ -38,40 +38,10 @@ namespace Game.Entities { public partial class Player { - void _LoadInventory(SQLResult result, SQLResult artifactsResult, uint timeDiff) + void _LoadInventory(SQLResult result, SQLResult artifactsResult, SQLResult azeriteResult, uint timeDiff) { - // 0 1 2 3 4 5 - // SELECT a.itemGuid, a.xp, a.artifactAppearanceId, a.artifactTierId, ap.artifactPowerId, ap.purchasedRank FROM item_instance_artifact_powers ap LEFT JOIN item_instance_artifact a ON ap.itemGuid = a.itemGuid INNER JOIN character_inventory ci ON ci.item = ap.guid WHERE ci.guid = ? - var artifactData = new Dictionary>>(); - if (!artifactsResult.IsEmpty()) - { - do - { - var artifactDataEntry = Tuple.Create(artifactsResult.Read(1), artifactsResult.Read(2), artifactsResult.Read(3), new List()); - ArtifactPowerLoadInfo artifactPowerData = new ArtifactPowerLoadInfo(); - artifactPowerData.ArtifactPowerId = artifactsResult.Read(4); - artifactPowerData.PurchasedRank = artifactsResult.Read(5); - - ArtifactPowerRecord artifactPower = CliDB.ArtifactPowerStorage.LookupByKey(artifactPowerData.ArtifactPowerId); - if (artifactPower != null) - { - uint maxRank = artifactPower.MaxPurchasableRank; - // allow ARTIFACT_POWER_FLAG_FINAL to overflow maxrank here - needs to be handled in Item::CheckArtifactUnlock (will refund artifact power) - if (artifactPower.Flags.HasAnyFlag(ArtifactPowerFlag.MaxRankWithTier) && artifactPower.Tier < artifactDataEntry.Item3) - maxRank += artifactDataEntry.Item3 - artifactPower.Tier; - - if (artifactPowerData.PurchasedRank > maxRank) - artifactPowerData.PurchasedRank = (byte)maxRank; - - artifactPowerData.CurrentRankWithBonus = (byte)((artifactPower.Flags & ArtifactPowerFlag.First) == ArtifactPowerFlag.First ? 1 : 0); - - artifactDataEntry.Item4.Add(artifactPowerData); - } - - artifactData[ObjectGuid.Create(HighGuid.Item, artifactsResult.Read(0))] = artifactDataEntry; - - } while (artifactsResult.NextRow()); - } + Dictionary additionalData = new Dictionary(); + ItemAdditionalLoadInfo.Init(additionalData, artifactsResult, azeriteResult); if (!result.IsEmpty()) { @@ -88,13 +58,24 @@ namespace Game.Entities Item item = _LoadItem(trans, zoneId, timeDiff, result.GetFields()); if (item != null) { - var artifactDataPair = artifactData.LookupByKey(item.GetGUID()); - if (item.GetTemplate().GetArtifactID() != 0 && artifactDataPair != null) - item.LoadArtifactData(this, artifactDataPair.Item1, artifactDataPair.Item2, artifactDataPair.Item3, artifactDataPair.Item4); + var addionalData = additionalData.LookupByKey(item.GetGUID().GetCounter()); + if (addionalData != null) + { + if (item.GetTemplate().GetArtifactID() != 0 && addionalData.Artifact != null) + item.LoadArtifactData(this, addionalData.Artifact.Xp, addionalData.Artifact.ArtifactAppearanceId, addionalData.Artifact.ArtifactTierId, addionalData.Artifact.ArtifactPowers); - ulong counter = result.Read(46); + if (addionalData.AzeriteItem != null) + { + AzeriteItem azeriteItem = item.ToAzeriteItem(); + if (azeriteItem != null) + azeriteItem.LoadAzeriteItemData(addionalData.AzeriteItem); + } + } + + + ulong counter = result.Read(43); ObjectGuid bagGuid = counter != 0 ? ObjectGuid.Create(HighGuid.Item, counter) : ObjectGuid.Empty; - byte slot = result.Read(47); + byte slot = result.Read(44); GetSession().GetCollectionMgr().CheckHeirloomUpgrades(item); GetSession().GetCollectionMgr().AddItemAppearance(item); @@ -1158,6 +1139,8 @@ namespace Game.Entities stmt.AddValue(0, GetGUID().GetCounter()); SQLResult result = DB.Characters.Query(stmt); + Dictionary mailById = new Dictionary(); + if (!result.IsEmpty()) { do @@ -1170,14 +1153,13 @@ namespace Game.Entities m.receiver = result.Read(3); m.subject = result.Read(4); m.body = result.Read(5); - bool has_items = result.Read(6); - m.expire_time = result.Read(7); - m.deliver_time = result.Read(8); - m.money = result.Read(9); - m.COD = result.Read(10); - m.checkMask = (MailCheckMask)result.Read(11); - m.stationery = (MailStationery)result.Read(12); - m.mailTemplateId = result.Read(13); + m.expire_time = result.Read(6); + m.deliver_time = result.Read(7); + m.money = result.Read(8); + m.COD = result.Read(9); + m.checkMask = (MailCheckMask)result.Read(10); + m.stationery = (MailStationery)result.Read(11); + m.mailTemplateId = result.Read(12); if (m.mailTemplateId != 0 && !CliDB.MailTemplateStorage.ContainsKey(m.mailTemplateId)) { @@ -1187,65 +1169,92 @@ namespace Game.Entities m.state = MailState.Unchanged; - if (has_items) - _LoadMailedItems(m); - m_mail.Add(m); + mailById[m.messageID] = m; } while (result.NextRow()); } + + stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_MAILITEMS); + stmt.AddValue(0, GetGUID().GetCounter()); + result = DB.Characters.Query(stmt); + + if (!result.IsEmpty()) + { + stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_MAILITEMS_ARTIFACT); + stmt.AddValue(0, GetGUID().GetCounter()); + SQLResult artifactResult = DB.Characters.Query(stmt); + + stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_MAILITEMS_AZERITE); + stmt.AddValue(0, GetGUID().GetCounter()); + SQLResult azeriteResult = DB.Characters.Query(stmt); + + Dictionary additionalData = new Dictionary(); + ItemAdditionalLoadInfo.Init(additionalData, artifactResult, azeriteResult); + + do + { + uint mailId = result.Read(44); + _LoadMailedItem(mailById[mailId], result.GetFields(), additionalData.LookupByKey(result.Read(0))); + } + while (result.NextRow()); + } + m_mailsLoaded = true; } - void _LoadMailedItems(Mail mail) + void _LoadMailedItem(Mail mail, SQLFields fields, ItemAdditionalLoadInfo additionalLoadInfo) { - // data needs to be at first place for Item.LoadFromDB - PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_MAILITEMS); - stmt.AddValue(0, mail.messageID); - SQLResult result = DB.Characters.Query(stmt); - if (result.IsEmpty()) - return; + ulong itemGuid = fields.Read(0); + uint itemEntry = fields.Read(1); - do + mail.AddItem(itemGuid, itemEntry); + + ItemTemplate proto = Global.ObjectMgr.GetItemTemplate(itemEntry); + if (proto == null) { - ulong itemGuid = result.Read(0); - uint itemEntry = result.Read(1); + Log.outError(LogFilter.Player, "Player {0} has unknown item_template (ProtoType) in mailed items(GUID: {1} template: {2}) in mail ({3}), deleted.", GetGUID().ToString(), itemGuid, itemEntry, mail.messageID); - mail.AddItem(itemGuid, itemEntry); + PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_INVALID_MAIL_ITEM); + stmt.AddValue(0, itemGuid); + DB.Characters.Execute(stmt); - ItemTemplate proto = Global.ObjectMgr.GetItemTemplate(itemEntry); - if (proto == null) - { - Log.outError(LogFilter.Player, "Player {0} has unknown item_template (ProtoType) in mailed items(GUID: {1} template: {2}) in mail ({3}), deleted.", GetGUID().ToString(), itemGuid, itemEntry, mail.messageID); - - stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_INVALID_MAIL_ITEM); - stmt.AddValue(0, itemGuid); - DB.Characters.Execute(stmt); - - stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEM_INSTANCE); - stmt.AddValue(0, itemGuid); - DB.Characters.Execute(stmt); - continue; - } - - Item item = Bag.NewItemOrBag(proto); - ObjectGuid ownerGuid = result.Read(46) != 0 ? ObjectGuid.Create(HighGuid.Player, result.Read(46)) : ObjectGuid.Empty; - if (!item.LoadFromDB(itemGuid, ownerGuid, result.GetFields(), itemEntry)) - { - Log.outError(LogFilter.Player, "Player:_LoadMailedItems - Item in mail ({0}) doesn't exist !!!! - item guid: {1}, deleted from mail", mail.messageID, itemGuid); - - stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_MAIL_ITEM); - stmt.AddValue(0, itemGuid); - DB.Characters.Execute(stmt); - - item.FSetState(ItemUpdateState.Removed); - - item.SaveToDB(null); // it also deletes item object ! - continue; - } - - AddMItem(item); + stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEM_INSTANCE); + stmt.AddValue(0, itemGuid); + DB.Characters.Execute(stmt); + return; } - while (result.NextRow()); + + Item item = Bag.NewItemOrBag(proto); + ObjectGuid ownerGuid = fields.Read(43) != 0 ? ObjectGuid.Create(HighGuid.Player, fields.Read(43)) : ObjectGuid.Empty; + if (!item.LoadFromDB(itemGuid, ownerGuid, fields, itemEntry)) + { + Log.outError(LogFilter.Player, "Player:_LoadMailedItem - Item in mail ({0}) doesn't exist !!!! - item guid: {1}, deleted from mail", mail.messageID, itemGuid); + + PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_MAIL_ITEM); + stmt.AddValue(0, itemGuid); + DB.Characters.Execute(stmt); + + item.FSetState(ItemUpdateState.Removed); + + item.SaveToDB(null); // it also deletes item object ! + return; + } + + if (additionalLoadInfo != null) + { + if (item.GetTemplate().GetArtifactID() != 0 && additionalLoadInfo.Artifact != null) + item.LoadArtifactData(this, additionalLoadInfo.Artifact.Xp, additionalLoadInfo.Artifact.ArtifactAppearanceId, + additionalLoadInfo.Artifact.ArtifactTierId, additionalLoadInfo.Artifact.ArtifactPowers); + + if (additionalLoadInfo.AzeriteItem != null) + { + AzeriteItem azeriteItem = item.ToAzeriteItem(); + if (azeriteItem != null) + azeriteItem.LoadAzeriteItemData(additionalLoadInfo.AzeriteItem); + } + } + + AddMItem(item); } void _LoadDeclinedNames(SQLResult result) { @@ -2889,7 +2898,7 @@ namespace Game.Entities // must be before inventory (some items required reputation check) reputationMgr.LoadFromDB(holder.GetResult(PlayerLoginQueryLoad.Reputation)); - _LoadInventory(holder.GetResult(PlayerLoginQueryLoad.Inventory), holder.GetResult(PlayerLoginQueryLoad.Artifacts), time_diff); + _LoadInventory(holder.GetResult(PlayerLoginQueryLoad.Inventory), holder.GetResult(PlayerLoginQueryLoad.Artifacts), holder.GetResult(PlayerLoginQueryLoad.LoadAzerite), time_diff); if (IsVoidStorageUnlocked()) _LoadVoidStorage(holder.GetResult(PlayerLoginQueryLoad.VoidStorage)); diff --git a/Source/Game/Guilds/Guild.cs b/Source/Game/Guilds/Guild.cs index f53a12f30..742ebc96e 100644 --- a/Source/Game/Guilds/Guild.cs +++ b/Source/Game/Guilds/Guild.cs @@ -1338,7 +1338,7 @@ namespace Game.Guilds public bool LoadBankItemFromDB(SQLFields field) { - byte tabId = field.Read(47); + byte tabId = field.Read(44); if (tabId >= _GetPurchasedTabsSize()) { Log.outError(LogFilter.Guild, "Invalid tab for item (GUID: {0}, id: {1}) in guild bank, skipped.", @@ -3241,7 +3241,7 @@ namespace Game.Guilds public bool LoadItemFromDB(SQLFields field) { - byte slotId = field.Read(48); + byte slotId = field.Read(45); uint itemGuid = field.Read(0); uint itemEntry = field.Read(1); if (slotId >= GuildConst.MaxBankSlots) diff --git a/Source/Game/Guilds/GuildManager.cs b/Source/Game/Guilds/GuildManager.cs index fe30c9b8d..62cab0177 100644 --- a/Source/Game/Guilds/GuildManager.cs +++ b/Source/Game/Guilds/GuildManager.cs @@ -382,7 +382,7 @@ namespace Game uint count = 0; do { - ulong guildId = result.Read(46); + ulong guildId = result.Read(43); Guild guild = GetGuildById(guildId); if (guild) guild.LoadBankItemFromDB(result.GetFields()); diff --git a/Source/Game/Handlers/CharacterHandler.cs b/Source/Game/Handlers/CharacterHandler.cs index 4197a214b..9a44d2324 100644 --- a/Source/Game/Handlers/CharacterHandler.cs +++ b/Source/Game/Handlers/CharacterHandler.cs @@ -2459,6 +2459,10 @@ namespace Game stmt.AddValue(0, lowGuid); SetQuery(PlayerLoginQueryLoad.Artifacts, stmt); + stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_ITEM_INSTANCE_AZERITE); + stmt.AddValue(0, lowGuid); + SetQuery(PlayerLoginQueryLoad.LoadAzerite, stmt); + stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHAR_VOID_STORAGE); stmt.AddValue(0, lowGuid); SetQuery(PlayerLoginQueryLoad.VoidStorage, stmt); @@ -2621,6 +2625,7 @@ namespace Game Reputation, Inventory, Artifacts, + LoadAzerite, Actions, MailCount, MailDate, diff --git a/Source/Game/Network/Packets/AzeriteItemPackets.cs b/Source/Game/Network/Packets/AzeritePackets.cs similarity index 100% rename from Source/Game/Network/Packets/AzeriteItemPackets.cs rename to Source/Game/Network/Packets/AzeritePackets.cs