diff options
author | Shauren <shauren.trinity@gmail.com> | 2022-09-14 20:49:38 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2022-09-14 20:49:38 +0200 |
commit | f19f32f2a49cf0eb235f1aa12106322bf9db2a15 (patch) | |
tree | 1c01c7b4f087777b9e57d039bf40e3987957dc35 /src/server | |
parent | d0a5d04c4c8f17ecd0ba6efaa114da051d303155 (diff) |
Core/Loot: Store references to Loot objects directly in players loot view map instead of guids of world objects holding that loot
Diffstat (limited to 'src/server')
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 37 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 8 | ||||
-rw-r--r-- | src/server/game/Handlers/LootHandler.cpp | 185 | ||||
-rw-r--r-- | src/server/game/Loot/Loot.cpp | 5 | ||||
-rw-r--r-- | src/server/game/Server/WorldSession.h | 3 |
5 files changed, 49 insertions, 189 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 9e5cf7b1371..9bd1c78d664 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -8704,31 +8704,13 @@ void Player::ApplyAllAzeriteEmpoweredItemMods(bool apply) } } -ObjectGuid Player::GetLootWorldObjectGUID(ObjectGuid const& lootObjectGuid) const +Loot* Player::GetLootByWorldObjectGUID(ObjectGuid const& lootWorldObjectGuid) const { - auto itr = m_AELootView.find(lootObjectGuid); - if (itr != m_AELootView.end()) - return itr->second; - - return ObjectGuid::Empty; -} - -void Player::RemoveAELootedWorldObject(ObjectGuid const& lootWorldObjectGuid) -{ - auto itr = std::find_if(m_AELootView.begin(), m_AELootView.end(), [&lootWorldObjectGuid](std::pair<ObjectGuid const, ObjectGuid> const& lootView) + auto itr = std::find_if(m_AELootView.begin(), m_AELootView.end(), [&lootWorldObjectGuid](std::pair<ObjectGuid const, Loot*> const& lootView) { - return lootView.second == lootWorldObjectGuid; - }); - if (itr != m_AELootView.end()) - m_AELootView.erase(itr); -} - -bool Player::HasLootWorldObjectGUID(ObjectGuid const& lootWorldObjectGuid) const -{ - return m_AELootView.end() != std::find_if(m_AELootView.begin(), m_AELootView.end(), [&lootWorldObjectGuid](std::pair<ObjectGuid const, ObjectGuid> const& lootView) - { - return lootView.second == lootWorldObjectGuid; + return lootView.second->GetOwnerGUID() == lootWorldObjectGuid; }); + return itr != m_AELootView.end() ? itr->second : nullptr; } /* If in a battleground a player dies, and an enemy removes the insignia, the player's bones is lootable @@ -8860,8 +8842,6 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa if (lootid) { - loot->clear(); - Group* group = GetGroup(); bool groupRules = (group && go->GetGOInfo()->type == GAMEOBJECT_TYPE_CHEST && go->GetGOInfo()->chest.usegrouplootrules); @@ -9018,8 +8998,9 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa if (creature->CanGeneratePickPocketLoot()) { creature->StartPickPocketRefillTimer(); - loot->clear(); + loot = new Loot(GetMap(), creature->GetGUID(), LOOT_PICKPOCKETING); + creature->m_loot.reset(loot); if (uint32 lootid = creature->GetCreatureTemplate()->pickpocketLootId) loot->FillLoot(lootid, LootTemplates_Pickpocketing, this, true); @@ -9151,7 +9132,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa // 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 == LOOT_CORPSE && !guid.IsItem()) SetUnitFlag(UNIT_FLAG_LOOTING); @@ -13052,7 +13033,7 @@ void Player::SwapItem(uint16 src, uint16 dst) { if (Item* bagItem = bag->GetItemByPos(i)) { - if (HasLootWorldObjectGUID(bagItem->GetGUID())) + if (GetLootByWorldObjectGUID(bagItem->GetGUID())) { m_session->DoLootReleaseAll(); released = true; // so we don't need to look at dstBag @@ -13069,7 +13050,7 @@ void Player::SwapItem(uint16 src, uint16 dst) { if (Item* bagItem = bag->GetItemByPos(i)) { - if (HasLootWorldObjectGUID(bagItem->GetGUID())) + if (GetLootByWorldObjectGUID(bagItem->GetGUID())) { m_session->DoLootReleaseAll(); break; diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 40eaae73828..9b52a94a6d0 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2062,10 +2062,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> ObjectGuid const& GetLootGUID() const { return m_playerData->LootTargetGUID; } void SetLootGUID(ObjectGuid const& guid) { SetUpdateFieldValue(m_values.ModifyValue(&Player::m_playerData).ModifyValue(&UF::PlayerData::LootTargetGUID), guid); } - ObjectGuid GetLootWorldObjectGUID(ObjectGuid const& lootObjectGuid) const; - void RemoveAELootedWorldObject(ObjectGuid const& lootWorldObjectGuid); - bool HasLootWorldObjectGUID(ObjectGuid const& lootWorldObjectGuid) const; - std::unordered_map<ObjectGuid, ObjectGuid> const& GetAELootView() const { return m_AELootView; } + Loot* GetLootByWorldObjectGUID(ObjectGuid const& lootWorldObjectGuid) const; + std::unordered_map<ObjectGuid, Loot*> const& GetAELootView() const { return m_AELootView; } void RemovedInsignia(Player* looterPlr); @@ -3178,7 +3176,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> SceneMgr m_sceneMgr; - std::unordered_map<ObjectGuid /*LootObject*/, ObjectGuid /*world object*/> m_AELootView; + std::unordered_map<ObjectGuid /*LootObject*/, Loot*> m_AELootView; void _InitHonorLevelOnLoadFromDB(uint32 honor, uint32 honorLevel); std::unique_ptr<RestMgr> _restMgr; diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp index 389e2e373dc..a22d40ff2b1 100644 --- a/src/server/game/Handlers/LootHandler.cpp +++ b/src/server/game/Handlers/LootHandler.cpp @@ -70,8 +70,14 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPackets::Loot::LootItem& p /// @todo Implement looting by LootObject guid for (WorldPackets::Loot::LootRequest const& req : packet.Loot) { - Loot* loot = nullptr; - ObjectGuid lguid = player->GetLootWorldObjectGUID(req.Object); + Loot* loot = Trinity::Containers::MapGetValuePtr(player->GetAELootView(), req.Object); + if (!loot) + { + player->SendLootRelease(ObjectGuid::Empty); + continue; + } + + ObjectGuid lguid = loot->GetOwnerGUID(); if (lguid.IsGameObject()) { @@ -83,33 +89,8 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPackets::Loot::LootItem& p 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 = GetPlayer()->GetMap()->GetCreature(lguid); if (!creature) @@ -123,26 +104,13 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPackets::Loot::LootItem& p player->SendLootError(req.Object, lguid, LOOT_ERROR_TOO_FAR); continue; } - - loot = creature->GetLootForPlayer(player); - if (creature->IsAlive() != (loot && loot->loot_type == LOOT_PICKPOCKETING)) - { - player->SendLootError(req.Object, lguid, LOOT_ERROR_DIDNT_KILL); - continue; - } - } - - if (!loot) - { - player->SendLootRelease(lguid); - continue; } player->StoreLootItem(lguid, req.LootListID - 1, loot, aeResultPtr); // 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 (aeResultPtr) @@ -162,78 +130,11 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPackets::Loot::LootItem& p void WorldSession::HandleLootMoneyOpcode(WorldPackets::Loot::LootMoney& /*packet*/) { Player* player = GetPlayer(); - for (std::pair<ObjectGuid const, ObjectGuid> const& lootView : player->GetAELootView()) + for (std::pair<ObjectGuid const, Loot*> const& lootView : player->GetAELootView()) { - ObjectGuid guid = lootView.second; - Loot* loot = nullptr; - bool shareMoney = true; - - switch (guid.GetHigh()) - { - case HighGuid::GameObject: - { - GameObject* go = GetPlayer()->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, INTERACTION_DISTANCE)) - { - loot = bones->GetLootForPlayer(player); - shareMoney = false; - } - - break; - } - case HighGuid::Item: - { - if (Item* item = player->GetItemByGuid(guid)) - { - loot = item->GetLootForPlayer(player); - shareMoney = false; - } - break; - } - case HighGuid::Creature: - case HighGuid::Vehicle: - { - Creature* creature = player->GetMap()->GetCreature(guid); - if (!creature) - { - player->SendLootError(lootView.first, guid, LOOT_ERROR_NO_LOOT); - continue; - } - - if (!creature->IsWithinDistInMap(player, AELootCreatureCheck::LootDistance)) - { - player->SendLootError(lootView.first, guid, LOOT_ERROR_TOO_FAR); - continue; - } - - loot = creature->GetLootForPlayer(player); - if (creature->IsAlive() != (loot && loot->loot_type == LOOT_PICKPOCKETING)) - { - player->SendLootError(lootView.first, guid, LOOT_ERROR_DIDNT_KILL); - continue; - } - - if (loot && loot->loot_type != LOOT_CORPSE) - shareMoney = false; - break; - } - default: - continue; // unlootable type - } - - if (!loot) - continue; + Loot* loot = lootView.second; + ObjectGuid guid = loot->GetOwnerGUID(); + bool shareMoney = loot->loot_type == LOOT_CORPSE; loot->NotifyMoneyRemoved(player->GetMap()); if (shareMoney && player->GetGroup()) //item, pickpocket and players can be looted only single player @@ -289,7 +190,7 @@ void WorldSession::HandleLootMoneyOpcode(WorldPackets::Loot::LootMoney& /*packet // Delete container if empty if (loot->isLooted() && guid.IsItem()) - player->GetSession()->DoLootRelease(guid); + player->GetSession()->DoLootRelease(loot); } } @@ -332,20 +233,20 @@ void WorldSession::HandleLootReleaseOpcode(WorldPackets::Loot::LootRelease& pack { // 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); + if (Loot* loot = GetPlayer()->GetLootByWorldObjectGUID(packet.Unit)) + DoLootRelease(loot); } -void WorldSession::DoLootRelease(ObjectGuid lguid) +void WorldSession::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->m_AELootView.erase(loot->GetGUID()); if (player->GetAELootView().empty()) player->RemoveUnitFlag(UNIT_FLAG_LOOTING); @@ -361,8 +262,6 @@ void WorldSession::DoLootRelease(ObjectGuid lguid) if (!go || ((go->GetOwnerGUID() != player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(player))) return; - loot = go->GetLootForPlayer(player); - if (go->GetGoType() == GAMEOBJECT_TYPE_DOOR) { // locked doors are opened with spelleffect openlock, prevent remove its as looted @@ -399,11 +298,9 @@ void WorldSession::DoLootRelease(ObjectGuid lguid) if (!corpse || !corpse->IsWithinDistInMap(player, INTERACTION_DISTANCE)) return; - loot = corpse->GetLootForPlayer(player); - - if (loot && loot->isLooted()) + if (loot->isLooted()) { - loot->clear(); + corpse->m_loot = nullptr; corpse->RemoveCorpseDynamicFlag(CORPSE_DYNFLAG_LOOTABLE); } } @@ -415,10 +312,8 @@ void WorldSession::DoLootRelease(ObjectGuid lguid) ItemTemplate const* proto = pItem->GetTemplate(); - loot = pItem->GetLootForPlayer(player); - // destroy only 5 items from stack in case prospecting and milling - if (loot && (loot->loot_type == LOOT_PROSPECTING || loot->loot_type == LOOT_MILLING)) + if (loot->loot_type == LOOT_PROSPECTING || loot->loot_type == LOOT_MILLING) { pItem->m_lootGenerated = false; pItem->m_loot.reset(); @@ -434,7 +329,7 @@ void WorldSession::DoLootRelease(ObjectGuid lguid) 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 && loot->isLooted()) || !proto->HasFlag(ITEM_FLAG_HAS_LOOT)) + if (loot->isLooted() || !proto->HasFlag(ITEM_FLAG_HAS_LOOT)) player->DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), true); } return; // item can be looted only single player @@ -448,11 +343,10 @@ void WorldSession::DoLootRelease(ObjectGuid lguid) if (!creature->IsWithinDistInMap(player, AELootCreatureCheck::LootDistance)) return; - loot = creature->GetLootForPlayer(player); if (creature->IsAlive() != (loot && loot->loot_type == LOOT_PICKPOCKETING)) return; - if (!loot || loot->isLooted()) + if (loot->isLooted()) { creature->RemoveDynamicFlag(UNIT_DYNFLAG_LOOTABLE); @@ -476,15 +370,14 @@ void WorldSession::DoLootRelease(ObjectGuid lguid) } //Player is not looking at loot list, he doesn't need to see updates on the loot list - if (loot) - loot->RemoveLooter(player->GetGUID()); + loot->RemoveLooter(player->GetGUID()); } void WorldSession::DoLootReleaseAll() { - std::unordered_map<ObjectGuid, ObjectGuid> lootView = _player->GetAELootView(); - for (std::pair<ObjectGuid const, ObjectGuid> const& lootPair : lootView) - DoLootRelease(lootPair.second); + std::unordered_map<ObjectGuid, Loot*> lootView = _player->GetAELootView(); + for (auto const& [lootGuid, loot] : lootView) + DoLootRelease(loot); } void WorldSession::HandleLootMasterGiveOpcode(WorldPackets::Loot::MasterLootItem& masterLootItem) @@ -509,8 +402,7 @@ void WorldSession::HandleLootMasterGiveOpcode(WorldPackets::Loot::MasterLootItem for (WorldPackets::Loot::LootRequest const& req : masterLootItem.Loot) { - Loot* loot = nullptr; - ObjectGuid lootguid = _player->GetLootWorldObjectGUID(req.Object); + Loot* loot = Trinity::Containers::MapGetValuePtr(_player->GetAELootView(), req.Object); if (!_player->IsInRaidWith(target) || !_player->IsInMap(target)) { @@ -519,23 +411,6 @@ void WorldSession::HandleLootMasterGiveOpcode(WorldPackets::Loot::MasterLootItem 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) return; diff --git a/src/server/game/Loot/Loot.cpp b/src/server/game/Loot/Loot.cpp index 70d3da25e8f..f1355edda87 100644 --- a/src/server/game/Loot/Loot.cpp +++ b/src/server/game/Loot/Loot.cpp @@ -29,6 +29,7 @@ #include "Player.h" #include "Random.h" #include "World.h" +#include "WorldSession.h" // // --------- LootItem --------- @@ -151,7 +152,11 @@ void Loot::clear() delete itr->second; PlayerNonQuestNonFFAConditionalItems.clear(); + for (ObjectGuid playerGuid : PlayersLooting) + if (Player* player = ObjectAccessor::FindConnectedPlayer(playerGuid)) + player->GetSession()->DoLootRelease(this); PlayersLooting.clear(); + items.clear(); quest_items.clear(); gold = 0; diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 4b267810455..05e376b8e70 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -56,6 +56,7 @@ struct BlackMarketTemplate; struct ChrCustomizationReqEntry; struct DeclinedName; struct ItemTemplate; +struct Loot; struct MovementInfo; struct Petition; struct Position; @@ -1115,7 +1116,7 @@ class TC_GAME_API WorldSession // Guild/Arena Team void SendPetitionShowList(ObjectGuid guid); - void DoLootRelease(ObjectGuid lguid); + void DoLootRelease(Loot* loot); void DoLootReleaseAll(); // Account mute time |