mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-16 07:30:42 +01:00
Core/Loot: Store references to Loot objects directly in players loot view map instead of guids of world objects holding that loot
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user