From b4ea5a6d19264d3b09478f089930c0dd5199b03c Mon Sep 17 00:00:00 2001 From: ApoC Date: Wed, 21 Oct 2009 22:54:26 +0200 Subject: [PATCH] [8701] Fixes and inprovements in pool system. * Fixed object is removed from guid->object map but still spawned in world under some conditions * Fixed possibility to spawn already spawned object * Fixed objects despawning (missing part for explicitly chanced objects added) Signed-off-by: ApoC --- src/game/Creature.cpp | 2 +- src/game/GameEventMgr.cpp | 4 +- src/game/PoolHandler.cpp | 217 ++++++++++++++++++++------------------ src/game/PoolHandler.h | 11 +- src/shared/revision_nr.h | 2 +- 5 files changed, 123 insertions(+), 113 deletions(-) diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index 2a195e7d0..f82474f83 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -369,7 +369,7 @@ void Creature::Update(uint32 diff) uint16 poolid = poolhandler.IsPartOfAPool(GetGUIDLow(), GetTypeId()); if (poolid) - poolhandler.UpdatePool(poolid, GetGUIDLow(), GetTypeId()); + poolhandler.UpdatePool(poolid, GetGUIDLow(), TYPEID_UNIT); else GetMap()->Add(this); } diff --git a/src/game/GameEventMgr.cpp b/src/game/GameEventMgr.cpp index 24f9652bd..99b77722f 100644 --- a/src/game/GameEventMgr.cpp +++ b/src/game/GameEventMgr.cpp @@ -580,7 +580,9 @@ void GameEventMgr::GameEventSpawn(int16 event_id) for (IdList::iterator itr = mGameEventPoolIds[internal_event_id].begin();itr != mGameEventPoolIds[internal_event_id].end();++itr) { - poolhandler.SpawnPool(*itr); + poolhandler.SpawnPool(*itr, 0, 0); + poolhandler.SpawnPool(*itr, 0, TYPEID_GAMEOBJECT); + poolhandler.SpawnPool(*itr, 0, TYPEID_UNIT); } } diff --git a/src/game/PoolHandler.cpp b/src/game/PoolHandler.cpp index fe38d3f82..7824654cb 100644 --- a/src/game/PoolHandler.cpp +++ b/src/game/PoolHandler.cpp @@ -28,13 +28,6 @@ INSTANTIATE_SINGLETON_1(PoolHandler); //////////////////////////////////////////////////////////// // Methods of template class PoolGroup -template -PoolGroup::PoolGroup() -{ - m_SpawnedPoolAmount = 0; - m_LastDespawnedNode = 0; -} - // Method to add a gameobject/creature guid to the proper list depending on pool type and chance value template void PoolGroup::AddEntry(PoolObject& poolitem, uint32 maxentries) @@ -64,35 +57,49 @@ bool PoolGroup::CheckPool(void) template bool PoolGroup::IsSpawnedObject(uint32 guid) { - for (uint32 i=0; i -uint32 PoolGroup::RollOne(void) +void PoolGroup::RollOne(int32& index, PoolObjectList** store, uint32 triggerFrom) { - if (!ExplicitlyChanced.empty()) // First explicitly chanced entries are checked + if (!ExplicitlyChanced.empty()) { - float roll = rand_chance(); + float roll = (float)rand_chance(); - for (uint32 i=0; i::RollOne(void) template void PoolGroup::DespawnObject(uint32 guid) { - for (size_t i=0; i < EqualChanced.size(); ++i) + for (size_t i = 0; i < EqualChanced.size(); ++i) { if (EqualChanced[i].spawned) { if (!guid || EqualChanced[i].guid == guid) { - if (guid) - m_LastDespawnedNode = EqualChanced[i].guid; - else - Despawn1Object(EqualChanced[i].guid); - + Despawn1Object(EqualChanced[i].guid); EqualChanced[i].spawned = false; if (m_SpawnedPoolAmount > 0) @@ -119,6 +122,21 @@ void PoolGroup::DespawnObject(uint32 guid) } } } + + for (size_t i = 0; i < ExplicitlyChanced.size(); ++i) + { + if (ExplicitlyChanced[i].spawned) + { + if (!guid || ExplicitlyChanced[i].guid == guid) + { + Despawn1Object(ExplicitlyChanced[i].guid); + ExplicitlyChanced[i].spawned = false; + + if (m_SpawnedPoolAmount > 0) + --m_SpawnedPoolAmount; + } + } + } } // Method that is actualy doing the removal job on one creature @@ -176,58 +194,48 @@ void PoolGroup::RemoveOneRelation(uint16 child_pool_id) } } -// Method that Spawn 1+ creatures or gameobject -// if cache is false (initialization or event start), X creatures are spawned with X <= limit (< if limit higher that the number of creatures in pool) -// if cache is true, this means only one has to be spawned (or respawned if the rolled one is same as cached one) template -void PoolGroup::SpawnObject(uint32 limit, bool cache) +void PoolGroup::SpawnObject(uint32 limit, uint32 triggerFrom) { - if (limit == 1) // This is the only case where explicit chance is used + uint32 lastDespawned = 0; + int count = limit - m_SpawnedPoolAmount; + + // If triggered from some object respawn this object is still marked as spawned + // and also counted into m_SpawnedPoolAmount so we need increase count to be + // spawned by 1 + if (triggerFrom) + ++count; + + // This will try to spawn the rest of pool, not guaranteed + for (int i = 0; i < count; ++i) { - uint32 roll = RollOne(); - if (!cache || (cache && m_LastDespawnedNode != roll)) + int index; + PoolObjectList* store; + + RollOne(index, &store, triggerFrom); + if (index == -1) + continue; + if ((*store)[index].guid == lastDespawned) + continue; + + if ((*store)[index].guid == triggerFrom) { - if (cache) - Despawn1Object(m_LastDespawnedNode); - Spawn1Object(roll); + (*store)[index].spawned = ReSpawn1Object(triggerFrom); + triggerFrom = 0; + continue; } else - ReSpawn1Object(roll); - m_LastDespawnedNode = 0; - } - else if (limit < EqualChanced.size() && m_SpawnedPoolAmount < limit) - { - std::vector IndexList; - for (size_t i = 0; i < EqualChanced.size(); ++i) - if (!EqualChanced[i].spawned) - IndexList.push_back(i); + (*store)[index].spawned = Spawn1Object((*store)[index].guid); - while (m_SpawnedPoolAmount < limit && IndexList.size() > 0) + if (triggerFrom) { - uint32 roll = urand(1, IndexList.size()) - 1; - uint32 index = IndexList[roll]; - if (!cache || (cache && EqualChanced[index].guid != m_LastDespawnedNode)) - { - if (cache) - Despawn1Object(m_LastDespawnedNode); - - EqualChanced[index].spawned = Spawn1Object(EqualChanced[index].guid); - } - else - EqualChanced[index].spawned = ReSpawn1Object(EqualChanced[index].guid); - - if (EqualChanced[index].spawned) - ++m_SpawnedPoolAmount; // limited group use the Spawned variable to store the number of actualy spawned creatures - - std::vector::iterator itr = IndexList.begin()+roll; - IndexList.erase(itr); + // One spawn one despawn no count increase + DespawnObject(triggerFrom); + lastDespawned = triggerFrom; + triggerFrom = 0; } - m_LastDespawnedNode = 0; - } - else // Not enough objects in pool, so spawn all - { - for (size_t i = 0; i < EqualChanced.size(); ++i) - EqualChanced[i].spawned = Spawn1Object(EqualChanced[i].guid); + else + ++m_SpawnedPoolAmount; } } @@ -235,8 +243,7 @@ void PoolGroup::SpawnObject(uint32 limit, bool cache) template <> bool PoolGroup::Spawn1Object(uint32 guid) { - CreatureData const* data = objmgr.GetCreatureData(guid); - if (data) + if (CreatureData const* data = objmgr.GetCreatureData(guid)) { objmgr.AddCreatureToGrid(guid, data); @@ -250,11 +257,10 @@ bool PoolGroup::Spawn1Object(uint32 guid) if (!pCreature->LoadFromDB(guid, map)) { delete pCreature; + return false; } else - { map->Add(pCreature); - } } return true; } @@ -265,8 +271,7 @@ bool PoolGroup::Spawn1Object(uint32 guid) template <> bool PoolGroup::Spawn1Object(uint32 guid) { - GameObjectData const* data = objmgr.GetGOData(guid); - if (data) + if (GameObjectData const* data = objmgr.GetGOData(guid)) { objmgr.AddGameobjectToGrid(guid, data); // Spawn if necessary (loaded grids only) @@ -280,6 +285,7 @@ bool PoolGroup::Spawn1Object(uint32 guid) if (!pGameobject->LoadFromDB(guid, map)) { delete pGameobject; + return false; } else { @@ -296,7 +302,9 @@ bool PoolGroup::Spawn1Object(uint32 guid) template <> bool PoolGroup::Spawn1Object(uint32 child_pool_id) { - poolhandler.SpawnPool(child_pool_id); + poolhandler.SpawnPool(child_pool_id, 0, 0); + poolhandler.SpawnPool(child_pool_id, 0, TYPEID_GAMEOBJECT); + poolhandler.SpawnPool(child_pool_id, 0, TYPEID_UNIT); return true; } @@ -304,8 +312,7 @@ bool PoolGroup::Spawn1Object(uint32 child_pool_id) template <> bool PoolGroup::ReSpawn1Object(uint32 guid) { - CreatureData const* data = objmgr.GetCreatureData(guid); - if (data) + if (CreatureData const* data = objmgr.GetCreatureData(guid)) { if (Creature* pCreature = ObjectAccessor::Instance().GetObjectInWorld(MAKE_NEW_GUID(guid, data->id, HIGHGUID_UNIT), (Creature*)NULL)) pCreature->GetMap()->Add(pCreature); @@ -318,8 +325,7 @@ bool PoolGroup::ReSpawn1Object(uint32 guid) template <> bool PoolGroup::ReSpawn1Object(uint32 guid) { - GameObjectData const* data = objmgr.GetGOData(guid); - if (data) + if (GameObjectData const* data = objmgr.GetGOData(guid)) { if (GameObject* pGameobject = ObjectAccessor::Instance().GetObjectInWorld(MAKE_NEW_GUID(guid, data->id, HIGHGUID_GAMEOBJECT), (GameObject*)NULL)) pGameobject->GetMap()->Add(pGameobject); @@ -628,7 +634,9 @@ void PoolHandler::Initialize() sLog.outErrorDb("Pool Id (%u) has all creatures or gameobjects with explicit chance sum <>100 and no equal chance defined. The pool system cannot pick one to spawn.", pool_entry); continue; } - SpawnPool(pool_entry); + SpawnPool(pool_entry, 0, 0); + SpawnPool(pool_entry, 0, TYPEID_GAMEOBJECT); + SpawnPool(pool_entry, 0, TYPEID_UNIT); count++; } while (result->NextRow()); delete result; @@ -640,25 +648,35 @@ void PoolHandler::Initialize() // Call to spawn a pool, if cache if true the method will spawn only if cached entry is different // If it's same, the gameobject/creature is respawned only (added back to map) -void PoolHandler::SpawnPool(uint16 pool_id, bool cache) +void PoolHandler::SpawnPool(uint16 pool_id, uint32 guid, uint32 type) { - if (!mPoolPoolGroups[pool_id].isEmpty()) - mPoolPoolGroups[pool_id].SpawnObject(mPoolTemplate[pool_id].MaxLimit, cache); - if (!mPoolGameobjectGroups[pool_id].isEmpty()) - mPoolGameobjectGroups[pool_id].SpawnObject(mPoolTemplate[pool_id].MaxLimit, cache); - if (!mPoolCreatureGroups[pool_id].isEmpty()) - mPoolCreatureGroups[pool_id].SpawnObject(mPoolTemplate[pool_id].MaxLimit, cache); + switch (type) + { + case TYPEID_UNIT: + if (!mPoolCreatureGroups[pool_id].isEmpty()) + mPoolCreatureGroups[pool_id].SpawnObject(mPoolTemplate[pool_id].MaxLimit, guid); + break; + case TYPEID_GAMEOBJECT: + if (!mPoolGameobjectGroups[pool_id].isEmpty()) + mPoolGameobjectGroups[pool_id].SpawnObject(mPoolTemplate[pool_id].MaxLimit, guid); + break; + default: + if (!mPoolPoolGroups[pool_id].isEmpty()) + mPoolPoolGroups[pool_id].SpawnObject(mPoolTemplate[pool_id].MaxLimit, guid); + } } // Call to despawn a pool, all gameobjects/creatures in this pool are removed void PoolHandler::DespawnPool(uint16 pool_id) { - if (!mPoolPoolGroups[pool_id].isEmpty()) - mPoolPoolGroups[pool_id].DespawnObject(); - if (!mPoolGameobjectGroups[pool_id].isEmpty()) - mPoolGameobjectGroups[pool_id].DespawnObject(); if (!mPoolCreatureGroups[pool_id].isEmpty()) mPoolCreatureGroups[pool_id].DespawnObject(); + + if (!mPoolGameobjectGroups[pool_id].isEmpty()) + mPoolGameobjectGroups[pool_id].DespawnObject(); + + if (!mPoolPoolGroups[pool_id].isEmpty()) + mPoolPoolGroups[pool_id].DespawnObject(); } // Call to update the pool when a gameobject/creature part of pool [pool_id] is ready to respawn @@ -666,19 +684,10 @@ void PoolHandler::DespawnPool(uint16 pool_id) // Then the spawn pool call will use this cache to decide void PoolHandler::UpdatePool(uint16 pool_id, uint32 guid, uint32 type) { - uint16 motherpoolid = IsPartOfAPool(pool_id, 0); - - if (motherpoolid) - mPoolPoolGroups[motherpoolid].DespawnObject(pool_id); - else if (type == TYPEID_GAMEOBJECT && !mPoolGameobjectGroups[pool_id].isEmpty()) - mPoolGameobjectGroups[pool_id].DespawnObject(guid); - else if (type != TYPEID_GAMEOBJECT && !mPoolCreatureGroups[pool_id].isEmpty()) - mPoolCreatureGroups[pool_id].DespawnObject(guid); - - if (motherpoolid) - SpawnPool(motherpoolid, true); + if (uint16 motherpoolid = IsPartOfAPool(pool_id, 0)) + SpawnPool(motherpoolid, 0, 0); else - SpawnPool(pool_id, true); + SpawnPool(pool_id, guid, type); } // Method that tell if the gameobject/creature is part of a pool and return the pool id if yes diff --git a/src/game/PoolHandler.h b/src/game/PoolHandler.h index 652d8e2cf..9ea0cd376 100644 --- a/src/game/PoolHandler.h +++ b/src/game/PoolHandler.h @@ -40,25 +40,24 @@ struct PoolObject template class PoolGroup { + typedef std::vector PoolObjectList; public: - PoolGroup(); + PoolGroup() : m_SpawnedPoolAmount(0) { } ~PoolGroup() {}; bool isEmpty() { return ExplicitlyChanced.empty() && EqualChanced.empty(); } void AddEntry(PoolObject& poolitem, uint32 maxentries); bool CheckPool(void); - uint32 RollOne(void); + void RollOne(int32& index, PoolObjectList** store, uint32 triggerFrom); bool IsSpawnedObject(uint32 guid); void DespawnObject(uint32 guid=0); void Despawn1Object(uint32 guid); - void SpawnObject(uint32 limit, bool cache=false); + void SpawnObject(uint32 limit, uint32 triggerFrom); bool Spawn1Object(uint32 guid); bool ReSpawn1Object(uint32 guid); void RemoveOneRelation(uint16 child_pool_id); private: - typedef std::vector PoolObjectList; PoolObjectList ExplicitlyChanced; PoolObjectList EqualChanced; - uint32 m_LastDespawnedNode; // Store the guid of the removed creature/gameobject during a pool update uint32 m_SpawnedPoolAmount; // Used to know the number of spawned objects }; @@ -75,7 +74,7 @@ class PoolHandler uint16 IsPartOfAPool(uint32 guid, uint32 type); bool IsSpawnedObject(uint16 pool_id, uint32 guid, uint32 type); bool CheckPool(uint16 pool_id); - void SpawnPool(uint16 pool_id, bool cache=false); + void SpawnPool(uint16 pool_id, uint32 guid, uint32 type); void DespawnPool(uint16 pool_id); void UpdatePool(uint16 pool_id, uint32 guid, uint32 type); void Initialize(); diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 40114edfa..abddd151e 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "8700" + #define REVISION_NR "8701" #endif // __REVISION_NR_H__