From bfdbcd7cbef3950fc01191fe391917a0de3b500e Mon Sep 17 00:00:00 2001 From: hondacrx Date: Sun, 18 Sep 2022 15:40:17 -0400 Subject: [PATCH] Core/Loot: Store references to Loot objects directly in players loot view map instead of guids of world objects holding that loot Port From (https://github.com/TrinityCore/TrinityCore/commit/f19f32f2a49cf0eb235f1aa12106322bf9db2a15) --- Source/Game/Entities/Player/Player.Fields.cs | 3 +- Source/Game/Entities/Player/Player.Items.cs | 34 +--- Source/Game/Handlers/LootHandler.cs | 186 +++---------------- Source/Game/Loot/Loot.cs | 7 + 4 files changed, 49 insertions(+), 181 deletions(-) diff --git a/Source/Game/Entities/Player/Player.Fields.cs b/Source/Game/Entities/Player/Player.Fields.cs index 2ca2eb94d..5ba8185da 100644 --- a/Source/Game/Entities/Player/Player.Fields.cs +++ b/Source/Game/Entities/Player/Player.Fields.cs @@ -22,6 +22,7 @@ using Game.Chat; using Game.DataStorage; using Game.Garrisons; using Game.Groups; +using Game.Loots; using Game.Mails; using Game.Maps; using Game.Misc; @@ -238,7 +239,7 @@ namespace Game.Entities SceneMgr m_sceneMgr; - Dictionary m_AELootView = new(); + Dictionary m_AELootView = new(); CUFProfile[] _CUFProfiles = new CUFProfile[PlayerConst.MaxCUFProfiles]; float[] m_powerFraction = new float[(int)PowerType.MaxPerClass]; diff --git a/Source/Game/Entities/Player/Player.Items.cs b/Source/Game/Entities/Player/Player.Items.cs index 1358c8e99..4b9a4945d 100644 --- a/Source/Game/Entities/Player/Player.Items.cs +++ b/Source/Game/Entities/Player/Player.Items.cs @@ -2404,7 +2404,7 @@ namespace Game.Entities Item bagItem = bag.GetItemByPos(i); if (bagItem != null) { - if (HasLootWorldObjectGUID(bagItem.GetGUID())) + if (GetLootByWorldObjectGUID(bagItem.GetGUID()) != null) { GetSession().DoLootReleaseAll(); released = true; // so we don't need to look at dstBag @@ -2422,7 +2422,7 @@ namespace Game.Entities Item bagItem = bag.GetItemByPos(i); if (bagItem != null) { - if (HasLootWorldObjectGUID(bagItem.GetGUID())) + if (GetLootByWorldObjectGUID(bagItem.GetGUID()) != null) { GetSession().DoLootReleaseAll(); break; @@ -4096,25 +4096,12 @@ namespace Game.Entities } } - public ObjectGuid GetLootWorldObjectGUID(ObjectGuid lootObjectGuid) + public Loot GetLootByWorldObjectGUID(ObjectGuid lootWorldObjectGuid) { - if (!m_AELootView.ContainsKey(lootObjectGuid)) - return ObjectGuid.Empty; + if (m_AELootView.TryGetValue(lootWorldObjectGuid, out Loot lootView)) + return lootView; - return m_AELootView[lootObjectGuid]; - } - - public void RemoveAELootedWorldObject(ObjectGuid lootWorldObjectGuid) - { - var itr = m_AELootView.FirstOrDefault(pair => pair.Value == lootWorldObjectGuid); - - if (itr.Key != ObjectGuid.Empty) - m_AELootView.Remove(itr.Key); - } - - public bool HasLootWorldObjectGUID(ObjectGuid lootWorldObjectGuid) - { - return m_AELootView.Any(lootView => lootView.Value == lootWorldObjectGuid); + return null; } //Inventory @@ -6073,7 +6060,7 @@ namespace Game.Entities SendEquipError(msg, null, null, item.itemid); } - public Dictionary GetAELootView() { return m_AELootView; } + public Dictionary GetAELootView() { return m_AELootView; } /// /// if in a Battleground a player dies, and an enemy removes the insignia, the player's bones is lootable @@ -6210,8 +6197,6 @@ namespace Game.Entities if (lootid != 0) { - loot.Clear(); - Group group = GetGroup(); bool groupRules = (group && go.GetGoInfo().type == GameObjectTypes.Chest && go.GetGoInfo().Chest.usegrouplootrules != 0); @@ -6373,8 +6358,9 @@ namespace Game.Entities if (creature.CanGeneratePickPocketLoot()) { creature.StartPickPocketRefillTimer(); - loot.Clear(); + loot = new Loot(GetMap(), creature.GetGUID(), LootType.Pickpocketing); + creature.loot = loot; uint lootid = creature.GetCreatureTemplate().PickPocketId; if (lootid != 0) loot.FillLoot(lootid, LootStorage.Pickpocketing, this, true); @@ -6510,7 +6496,7 @@ namespace Game.Entities // add 'this' player as one of the players that are looting 'loot' loot.AddLooter(GetGUID()); - m_AELootView[loot.GetGUID()] = guid; + m_AELootView[loot.GetGUID()] = loot; if (loot_type == LootType.Corpse && !guid.IsItem()) SetUnitFlag(UnitFlags.Looting); diff --git a/Source/Game/Handlers/LootHandler.cs b/Source/Game/Handlers/LootHandler.cs index c744d0e18..f2311fa42 100644 --- a/Source/Game/Handlers/LootHandler.cs +++ b/Source/Game/Handlers/LootHandler.cs @@ -39,8 +39,14 @@ namespace Game // @todo Implement looting by LootObject guid foreach (LootRequest req in packet.Loot) { - Loot loot = null; - ObjectGuid lguid = player.GetLootWorldObjectGUID(req.Object); + Loot loot = player.GetAELootView().LookupByKey(req.Object); + if (loot == null) + { + player.SendLootRelease(ObjectGuid.Empty); + continue; + } + + ObjectGuid lguid = loot.GetOwnerGUID(); if (lguid.IsGameObject()) { @@ -52,33 +58,8 @@ namespace Game player.SendLootRelease(lguid); continue; } - - loot = go.GetLootForPlayer(player); } - else if (lguid.IsItem()) - { - Item pItem = player.GetItemByGuid(lguid); - - if (!pItem) - { - player.SendLootRelease(lguid); - continue; - } - - loot = pItem.GetLootForPlayer(player); - } - else if (lguid.IsCorpse()) - { - Corpse bones = ObjectAccessor.GetCorpse(player, lguid); - if (!bones) - { - player.SendLootRelease(lguid); - continue; - } - - loot = bones.GetLootForPlayer(player); - } - else + else if (lguid.IsCreatureOrVehicle()) { Creature creature = player.GetMap().GetCreature(lguid); if (creature == null) @@ -92,26 +73,13 @@ namespace Game player.SendLootError(req.Object, lguid, LootError.TooFar); continue; } - - loot = creature.GetLootForPlayer(player); - if (creature.IsAlive() != (loot != null && loot.loot_type == LootType.Pickpocketing)) - { - player.SendLootError(req.Object, lguid, LootError.DidntKill); - continue; - } - } - - if (loot == null) - { - player.SendLootRelease(lguid); - continue; } player.StoreLootItem(lguid, (byte)(req.LootListID - 1), loot, aeResult); // If player is removing the last LootItem, delete the empty container. if (loot.IsLooted() && lguid.IsItem()) - player.GetSession().DoLootRelease(lguid); + player.GetSession().DoLootRelease(loot); } if (aeResult != null) @@ -135,82 +103,13 @@ namespace Game foreach (var lootView in player.GetAELootView()) { - ObjectGuid guid = lootView.Value; - Loot loot = null; - bool shareMoney = true; - - switch (guid.GetHigh()) - { - case HighGuid.GameObject: - { - GameObject go = player.GetMap().GetGameObject(guid); - - // do not check distance for GO if player is the owner of it (ex. fishing bobber) - if (go && (go.GetOwnerGUID() == player.GetGUID() || go.IsWithinDistInMap(player))) - loot = go.GetLootForPlayer(player); - - break; - } - case HighGuid.Corpse: // remove insignia ONLY in BG - { - Corpse bones = ObjectAccessor.GetCorpse(player, guid); - - if (bones && bones.IsWithinDistInMap(player, SharedConst.InteractionDistance)) - { - loot = bones.GetLootForPlayer(player); - shareMoney = false; - } - - break; - } - case HighGuid.Item: - { - Item item = player.GetItemByGuid(guid); - if (item) - { - loot = item.GetLootForPlayer(player); - shareMoney = false; - } - break; - } - case HighGuid.Creature: - case HighGuid.Vehicle: - { - Creature creature = player.GetMap().GetCreature(guid); - if (creature == null) - { - player.SendLootError(lootView.Key, guid, LootError.NoLoot); - continue; - } - - if (!creature.IsWithinDistInMap(player, AELootCreatureCheck.LootDistance)) - { - player.SendLootError(lootView.Key, guid, LootError.TooFar); - continue; - } - - loot = creature.GetLootForPlayer(player); - if (creature.IsAlive() != (loot != null && loot.loot_type == LootType.Pickpocketing)) - { - player.SendLootError(lootView.Key, guid, LootError.DidntKill); - continue; - } - - if (loot != null && loot.loot_type != LootType.Corpse) - shareMoney = false; - break; - } - default: - continue; // unlootable type - } - - if (loot == null) - continue; + Loot loot = lootView.Value; + ObjectGuid guid = loot.GetOwnerGUID(); + bool shareMoney = loot.loot_type == LootType.Corpse; loot.NotifyMoneyRemoved(player.GetMap()); if (shareMoney && player.GetGroup() != null) //item, pickpocket and players can be looted only single player { - Group group = player.GetGroup(); List playersNear = new(); @@ -262,7 +161,7 @@ namespace Game // Delete container if empty if (loot.IsLooted() && guid.IsItem()) - player.GetSession().DoLootRelease(guid); + player.GetSession().DoLootRelease(loot); } } @@ -335,20 +234,21 @@ namespace Game { // cheaters can modify lguid to prevent correct apply loot release code and re-loot // use internal stored guid - if (GetPlayer().HasLootWorldObjectGUID(packet.Unit)) - DoLootRelease(packet.Unit); + Loot loot = GetPlayer().GetLootByWorldObjectGUID(packet.Unit); + if (loot != null) + DoLootRelease(loot); } - public void DoLootRelease(ObjectGuid lguid) + public void DoLootRelease(Loot loot) { + ObjectGuid lguid = loot.GetOwnerGUID(); Player player = GetPlayer(); - Loot loot; if (player.GetLootGUID() == lguid) player.SetLootGUID(ObjectGuid.Empty); player.SendLootRelease(lguid); - player.RemoveAELootedWorldObject(lguid); + player.GetAELootView().Remove(loot.GetGUID()); if (player.GetAELootView().Empty()) player.RemoveUnitFlag(UnitFlags.Looting); @@ -364,8 +264,6 @@ namespace Game if (!go || ((go.GetOwnerGUID() != player.GetGUID() && go.GetGoType() != GameObjectTypes.FishingHole) && !go.IsWithinDistInMap(player))) return; - loot = go.GetLootForPlayer(player); - if (go.GetGoType() == GameObjectTypes.Door) { // locked doors are opened with spelleffect openlock, prevent remove its as looted @@ -402,11 +300,9 @@ namespace Game if (!corpse || !corpse.IsWithinDistInMap(player, SharedConst.InteractionDistance)) return; - loot = corpse.GetLootForPlayer(player); - - if (loot != null && loot.IsLooted()) + if (loot.IsLooted()) { - loot.Clear(); + corpse.loot = null; corpse.RemoveCorpseDynamicFlag(CorpseDynFlags.Lootable); } } @@ -418,10 +314,8 @@ namespace Game ItemTemplate proto = pItem.GetTemplate(); - loot = pItem.GetLootForPlayer(player); - // destroy only 5 items from stack in case prospecting and milling - if (loot != null && (loot.loot_type == LootType.Prospecting || loot.loot_type == LootType.Milling)) + if (loot.loot_type == LootType.Prospecting || loot.loot_type == LootType.Milling) { pItem.m_lootGenerated = false; pItem.loot = null; @@ -437,7 +331,7 @@ namespace Game else { // Only delete item if no loot or money (unlooted loot is saved to db) or if it isn't an openable item - if ((loot != null && loot.IsLooted()) || !proto.HasFlag(ItemFlags.HasLoot)) + if (loot.IsLooted() || !proto.HasFlag(ItemFlags.HasLoot)) player.DestroyItem(pItem.GetBagSlot(), pItem.GetSlot(), true); } return; // item can be looted only single player @@ -451,11 +345,10 @@ namespace Game if (!creature.IsWithinDistInMap(player, AELootCreatureCheck.LootDistance)) return; - loot = creature.GetLootForPlayer(player); if (creature.IsAlive() != (loot != null && loot.loot_type == LootType.Pickpocketing)) return; - if (loot == null || loot.IsLooted()) + if (loot.IsLooted()) { creature.RemoveDynamicFlag(UnitDynFlags.Lootable); @@ -484,15 +377,14 @@ namespace Game } //Player is not looking at loot list, he doesn't need to see updates on the loot list - if (loot != null) - loot.RemoveLooter(player.GetGUID()); + loot.RemoveLooter(player.GetGUID()); } public void DoLootReleaseAll() { - Dictionary lootView = _player.GetAELootView(); - foreach (var lootPair in lootView) - DoLootRelease(lootPair.Value); + Dictionary lootView = _player.GetAELootView(); + foreach (var (_, loot) in lootView) + DoLootRelease(loot); } [WorldPacketHandler(ClientOpcodes.MasterLootItem)] @@ -516,8 +408,7 @@ namespace Game foreach (LootRequest req in masterLootItem.Loot) { - Loot loot = null; - ObjectGuid lootguid = _player.GetLootWorldObjectGUID(req.Object); + Loot loot = _player.GetAELootView().LookupByKey(req.Object); if (!_player.IsInRaidWith(target) || !_player.IsInMap(target)) { @@ -526,23 +417,6 @@ namespace Game return; } - if (GetPlayer().GetLootGUID().IsCreatureOrVehicle()) - { - Creature creature = GetPlayer().GetMap().GetCreature(lootguid); - if (!creature) - return; - - loot = creature.GetLootForPlayer(_player); - } - else if (GetPlayer().GetLootGUID().IsGameObject()) - { - GameObject go = GetPlayer().GetMap().GetGameObject(lootguid); - if (!go) - return; - - loot = go.GetLootForPlayer(_player); - } - if (loot == null) return; diff --git a/Source/Game/Loot/Loot.cs b/Source/Game/Loot/Loot.cs index c2cdcb352..35b8196bf 100644 --- a/Source/Game/Loot/Loot.cs +++ b/Source/Game/Loot/Loot.cs @@ -815,6 +815,13 @@ namespace Game.Loots PlayerNonQuestNonFFAConditionalItems.Clear(); + foreach (ObjectGuid playerGuid in PlayersLooting) + { + Player player = Global.ObjAccessor.FindConnectedPlayer(playerGuid); + if (player != null) + player.GetSession().DoLootRelease(this); + } + PlayersLooting.Clear(); items.Clear(); quest_items.Clear();