Index: game/Group.cpp =================================================================== --- game/Group.cpp (revision 4889) +++ game/Group.cpp (working copy) @@ -51,6 +51,14 @@ else if(m_bgGroup->GetBgRaid(HORDE) == this) m_bgGroup->SetBgRaid(HORDE, NULL); else sLog.outError("Group::~Group: battleground group is not linked to the correct battleground."); } + Rolls::iterator itr; + while(!RollId.empty()) + { + itr = RollId.begin(); + Roll *r = *itr; + RollId.erase(itr); + delete(r); + } } bool Group::Create(const uint64 &guid, const char * name) @@ -392,12 +400,12 @@ //roll for over-threshold item if it's one-player loot if (item->Quality >= uint32(m_lootThreshold) && !i->freeforall) { - Roll r; + Roll* r=new Roll(); uint32 newitemGUID = objmgr.GenerateLowGuid(HIGHGUID_ITEM); - r.itemGUID = newitemGUID; - r.itemid = i->itemid; - r.itemRandomPropId = i->randomPropertyId; - r.itemRandomSuffix = i->randomSuffix; + r->itemGUID = newitemGUID; + r->itemid = i->itemid; + r->itemRandomPropId = i->randomPropertyId; + r->itemRandomSuffix = i->randomSuffix; //a vector is filled with only near party members for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next()) @@ -409,16 +417,16 @@ { if (member->GetDistance2dSq(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)) { - r.playerVote[member->GetGUID()] = NOT_EMITED_YET; - r.totalPlayersRolling++; + r->playerVote[member->GetGUID()] = NOT_EMITED_YET; + r->totalPlayersRolling++; } } } - r.loot = loot; - r.itemSlot = itemSlot; + r->setLoot(loot); + r->itemSlot = itemSlot; - group->SendLootStartRoll(newitemGUID, 60000, r); + group->SendLootStartRoll(newitemGUID, 60000, *r); loot->items[itemSlot].is_blocked = true; creature->m_groupLootTimer = 60000; @@ -447,12 +455,12 @@ //only roll for one-player items, not for ones everyone can get if (item->Quality >= uint32(m_lootThreshold) && !i->freeforall) { - Roll r; + Roll* r=new Roll(); uint32 newitemGUID = objmgr.GenerateLowGuid(HIGHGUID_ITEM); - r.itemGUID = newitemGUID; - r.itemid = i->itemid; - r.itemRandomPropId = i->randomPropertyId; - r.itemRandomSuffix = i->randomSuffix; + r->itemGUID = newitemGUID; + r->itemid = i->itemid; + r->itemRandomPropId = i->randomPropertyId; + r->itemRandomSuffix = i->randomSuffix; for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next()) { @@ -464,23 +472,27 @@ { if (playerToRoll->GetDistance2dSq(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)) { - r.playerVote[playerToRoll->GetGUID()] = NOT_EMITED_YET; - r.totalPlayersRolling++; + r->playerVote[playerToRoll->GetGUID()] = NOT_EMITED_YET; + r->totalPlayersRolling++; } } } - if (r.totalPlayersRolling > 0) + if (r->totalPlayersRolling > 0) { - r.loot = loot; - r.itemSlot = itemSlot; + r->setLoot(loot); + r->itemSlot = itemSlot; - group->SendLootStartRoll(newitemGUID, 60000, r); + group->SendLootStartRoll(newitemGUID, 60000, *r); loot->items[itemSlot].is_blocked = true; RollId.push_back(r); } + else + { + delete r; + } } else i->is_underthreshold=1; @@ -489,8 +501,9 @@ void Group::CountRollVote(uint64 playerGUID, uint64 Guid, uint32 NumberOfPlayers, uint8 Choise) { - Rolls::iterator roll = GetRoll(Guid); - if (roll == RollId.end()) + Rolls::iterator rollI = GetRoll(Guid); + Roll* roll = *rollI; + if (rollI == RollId.end()) return; Roll::PlayerVote::iterator itr = roll->playerVote.find(playerGUID); @@ -498,8 +511,8 @@ if (itr == roll->playerVote.end()) return; - if (roll->loot) - if (roll->loot->items.empty()) + if (roll->getLoot()) + if (roll->getLoot()->items.empty()) return; switch (Choise) @@ -528,7 +541,7 @@ } if (roll->totalPass + roll->totalGreed + roll->totalNeed >= roll->totalPlayersRolling) { - CountTheRoll(roll, NumberOfPlayers); + CountTheRoll(rollI, NumberOfPlayers); } } @@ -544,8 +557,15 @@ } } -void Group::CountTheRoll(Rolls::iterator roll, uint32 NumberOfPlayers) +void Group::CountTheRoll(Rolls::iterator rollI, uint32 NumberOfPlayers) { + Roll* roll = *rollI; + if(!roll->isValid()) // is loot already deleted ? + { + RollId.erase(rollI); + delete roll; + return; + } //end of the roll if (roll->totalNeed > 0) { @@ -574,13 +594,13 @@ if(player && player->GetSession()) { uint16 dest; - LootItem *item = &(roll->loot->items[roll->itemSlot]); + LootItem *item = &(roll->getLoot()->items[roll->itemSlot]); uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, roll->itemid, item->count, false ); if ( msg == EQUIP_ERR_OK ) { item->is_looted = true; - roll->loot->NotifyItemRemoved(roll->itemSlot); - roll->loot->unlootedCount--; + roll->getLoot()->NotifyItemRemoved(roll->itemSlot); + roll->getLoot()->unlootedCount--; player->StoreNewItem( dest, roll->itemid, item->count, true, item->randomPropertyId); } else @@ -619,13 +639,13 @@ if(player && player->GetSession()) { uint16 dest; - LootItem *item = &(roll->loot->items[roll->itemSlot]); + LootItem *item = &(roll->getLoot()->items[roll->itemSlot]); uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, roll->itemid, item->count, false ); if ( msg == EQUIP_ERR_OK ) { item->is_looted = true; - roll->loot->NotifyItemRemoved(roll->itemSlot); - roll->loot->unlootedCount--; + roll->getLoot()->NotifyItemRemoved(roll->itemSlot); + roll->getLoot()->unlootedCount--; player->StoreNewItem( dest, roll->itemid, item->count, true, item->randomPropertyId); } else @@ -639,10 +659,11 @@ else { SendLootAllPassed(roll->itemGUID, NumberOfPlayers, *roll); - LootItem *item = &(roll->loot->items[roll->itemSlot]); + LootItem *item = &(roll->getLoot()->items[roll->itemSlot]); if(item) item->is_blocked = false; } - RollId.erase(roll); + RollId.erase(rollI); + delete roll; } void Group::SetTargetIcon(uint8 id, uint64 guid) @@ -995,18 +1016,19 @@ { for (Rolls::iterator it = RollId.begin(); it < RollId.end(); it++) { - Roll::PlayerVote::iterator itr2 = it->playerVote.find(guid); - if(itr2 == it->playerVote.end()) + Roll* roll = *it; + Roll::PlayerVote::iterator itr2 = roll->playerVote.find(guid); + if(itr2 == roll->playerVote.end()) continue; - if (itr2->second == GREED) it->totalGreed--; - if (itr2->second == NEED) it->totalNeed--; - if (itr2->second == PASS) it->totalPass--; - if (itr2->second != NOT_VALID) it->totalPlayersRolling--; + if (itr2->second == GREED) roll->totalGreed--; + if (itr2->second == NEED) roll->totalNeed--; + if (itr2->second == PASS) roll->totalPass--; + if (itr2->second != NOT_VALID) roll->totalPlayersRolling--; - it->playerVote.erase(itr2); + roll->playerVote.erase(itr2); - CountRollVote(guid, it->itemGUID, GetMembersCount()-1, 3); + CountRollVote(guid, roll->itemGUID, GetMembersCount()-1, 3); } } @@ -1095,3 +1117,13 @@ SendUpdate(); } } + +//=================================================== +//============== Roll =============================== +//=================================================== + +void Roll::targetObjectBuildLink() +{ + // called from link() + this->getTarget()->addLootInvalidListener(this); +} Index: game/Group.h =================================================================== --- game/Group.h (revision 4889) +++ game/Group.h (working copy) @@ -21,6 +21,7 @@ #include "GroupReference.h" #include "GroupRefManager.h" +#include "LootMgr.h" #include #include @@ -100,6 +101,28 @@ //0, 1, 2, 3, 4, 5, 6, 7, 8, 9 static const uint8 GroupUpdateLength[GROUP_UPDATE_FLAGS_COUNT] = { 0, 1, 2, 2, 1, 2, 2, 2, 2, 4}; +class Roll : public LootInvalidListener +{ +public: + Roll(): itemGUID(0), itemid(0), itemRandomPropId(0), totalPlayersRolling(0), totalNeed(0), totalGreed(0), totalPass(0), itemSlot(0) {} + ~Roll() { } + void setLoot(Loot *pLoot) { link(pLoot, this); } + Loot *getLoot() { return getTarget(); } + void targetObjectBuildLink(); + + uint64 itemGUID; + uint32 itemid; + uint32 itemRandomSuffix; + int32 itemRandomPropId; + typedef std::map PlayerVote; + PlayerVote playerVote; //vote position correspond with player position (in group) + uint8 totalPlayersRolling; + uint8 totalNeed; + uint8 totalGreed; + uint8 totalPass; + uint8 itemSlot; +}; + /** request member stats checken **/ /** todo: uninvite people that not accepted invite **/ class MANGOS_DLL_SPEC Group @@ -118,26 +141,8 @@ typedef MemberSlotList::iterator member_witerator; typedef std::set InvitesList; - struct Roll - { - Roll(): itemGUID(0), itemid(0), itemRandomPropId(0), totalPlayersRolling(0), totalNeed(0), totalGreed(0), totalPass(0), loot(NULL), itemSlot(0) {} + typedef std::vector Rolls; - uint64 itemGUID; - uint32 itemid; - uint32 itemRandomSuffix; - int32 itemRandomPropId; - typedef std::map PlayerVote; - PlayerVote playerVote; //vote position correspond with player position (in group) - uint8 totalPlayersRolling; - uint8 totalNeed; - uint8 totalGreed; - uint8 totalPass; - Loot *loot; - uint8 itemSlot; - }; - - typedef std::vector Rolls; - public: Group(); ~Group(); @@ -271,7 +276,7 @@ Rolls::iterator iter; for (iter=RollId.begin(); iter != RollId.end(); ++iter) { - if (iter->itemGUID == Guid) + if ((*iter)->itemGUID == Guid) { return iter; } Index: game/LootMgr.cpp =================================================================== --- game/LootMgr.cpp (revision 4889) +++ game/LootMgr.cpp (working copy) @@ -556,6 +556,8 @@ return ql; } +//=================================================== + void Loot::NotifyItemRemoved(uint8 lootIndex) { // notify all players that are looting this that the item was removed Index: game/LootMgr.h =================================================================== --- game/LootMgr.h (revision 4889) +++ game/LootMgr.h (working copy) @@ -25,6 +25,7 @@ #include "ItemEnchantmentMgr.h" #include "ByteBuffer.h" #include "Util.h" +#include "Utilities/LinkedReference/RefManager.h" #include #include @@ -141,11 +142,41 @@ : index(_index), is_looted(_islooted) {} }; + typedef std::vector QuestItemList; typedef std::map QuestItemMap; typedef std::vector LootStoreItemList; typedef HM_NAMESPACE::hash_map LootStore; +//===================================================== + +struct Loot; +class LootInvalidListener : public Reference +{ +public: + LootInvalidListener() {} + void targetObjectDestroyLink() {} + void sourceObjectDestroyLink() {} +}; + +//===================================================== + +class LootInvalidRefManager : public RefManager +{ + public: + typedef LinkedListHead::Iterator< LootInvalidListener > iterator; + + LootInvalidListener* getFirst() { return (LootInvalidListener*)RefManager::getFirst(); } + LootInvalidListener* getLast() { return (LootInvalidListener*)RefManager::getLast(); } + + iterator begin() { return iterator(getFirst()); } + iterator end() { return iterator(NULL); } + iterator rbegin() { return iterator(getLast()); } + iterator rend() { return iterator(NULL); } +}; + +//===================================================== + struct Loot { std::set PlayersLooting; @@ -154,6 +185,8 @@ QuestItemMap PlayerNonQuestNonFFAConditionalItems; std::vector items; std::vector quest_items; + // All rolls are registered here. They need to know, when the loot is not valid anymore + LootInvalidRefManager i_LootInvalidRefManager; uint32 gold; uint8 unlootedCount; bool released; @@ -161,6 +194,13 @@ Loot(uint32 _gold = 0) : gold(_gold), unlootedCount(0), released(false) {} ~Loot() { clear(); } + // if loot becomes invalid this reference is used to inform the listener + void addLootInvalidListener(LootInvalidListener* pLootInvalidListener) + { + i_LootInvalidRefManager.insertFirst(pLootInvalidListener); + } + + // void clear(); void clear() { items.clear(); gold = 0; PlayersLooting.clear(); @@ -179,6 +219,7 @@ quest_items.clear(); gold = 0; unlootedCount = 0; + i_LootInvalidRefManager.clearReferences(); } bool empty() const { return items.empty() && gold == 0; }