[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 <apoc@nymfe.net>
This commit is contained in:
ApoC 2009-10-21 22:54:26 +02:00
parent f59f7d2a2e
commit b4ea5a6d19
5 changed files with 123 additions and 113 deletions

View file

@ -369,7 +369,7 @@ void Creature::Update(uint32 diff)
uint16 poolid = poolhandler.IsPartOfAPool(GetGUIDLow(), GetTypeId()); uint16 poolid = poolhandler.IsPartOfAPool(GetGUIDLow(), GetTypeId());
if (poolid) if (poolid)
poolhandler.UpdatePool(poolid, GetGUIDLow(), GetTypeId()); poolhandler.UpdatePool(poolid, GetGUIDLow(), TYPEID_UNIT);
else else
GetMap()->Add(this); GetMap()->Add(this);
} }

View file

@ -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) 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);
} }
} }

View file

@ -28,13 +28,6 @@ INSTANTIATE_SINGLETON_1(PoolHandler);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Methods of template class PoolGroup // Methods of template class PoolGroup
template <class T>
PoolGroup<T>::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 // Method to add a gameobject/creature guid to the proper list depending on pool type and chance value
template <class T> template <class T>
void PoolGroup<T>::AddEntry(PoolObject& poolitem, uint32 maxentries) void PoolGroup<T>::AddEntry(PoolObject& poolitem, uint32 maxentries)
@ -73,26 +66,40 @@ bool PoolGroup<T>::IsSpawnedObject(uint32 guid)
return false; return false;
} }
// Method that return a guid of a rolled creature or gameobject
// Note: Copy from loot system because it's very similar and only few things change
template <class T> template <class T>
uint32 PoolGroup<T>::RollOne(void) void PoolGroup<T>::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 < ExplicitlyChanced.size(); ++i) for (uint32 i = 0; i < ExplicitlyChanced.size(); ++i)
{ {
roll -= ExplicitlyChanced[i].chance; roll -= ExplicitlyChanced[i].chance;
if (roll < 0) // Triggering object is marked as spawned at this time and can be also rolled (respawn case)
return ExplicitlyChanced[i].guid; // so this need explicit check for this case
if (roll < 0 && (!ExplicitlyChanced[i].spawned || ExplicitlyChanced[i].guid == triggerFrom))
{
index = i;
*store = &ExplicitlyChanced;
return;
}
} }
} }
if (!EqualChanced.empty())
return EqualChanced[irand(0, EqualChanced.size()-1)].guid;
return 0; // None found if (!EqualChanced.empty())
{
index = irand(0, EqualChanced.size()-1);
// Triggering object is marked as spawned at this time and can be also rolled (respawn case)
// so this need explicit check for this case
if (!EqualChanced[index].spawned || EqualChanced[index].guid == triggerFrom)
{
*store = &EqualChanced;
return;
}
}
index = -1;
} }
// Main method to despawn a creature or gameobject in a pool // Main method to despawn a creature or gameobject in a pool
@ -107,11 +114,7 @@ void PoolGroup<T>::DespawnObject(uint32 guid)
{ {
if (!guid || EqualChanced[i].guid == guid) 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; EqualChanced[i].spawned = false;
if (m_SpawnedPoolAmount > 0) if (m_SpawnedPoolAmount > 0)
@ -119,6 +122,21 @@ void PoolGroup<T>::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 // Method that is actualy doing the removal job on one creature
@ -176,58 +194,48 @@ void PoolGroup<Pool>::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 <class T> template <class T>
void PoolGroup<T>::SpawnObject(uint32 limit, bool cache) void PoolGroup<T>::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(); int index;
if (!cache || (cache && m_LastDespawnedNode != roll)) PoolObjectList* store;
RollOne(index, &store, triggerFrom);
if (index == -1)
continue;
if ((*store)[index].guid == lastDespawned)
continue;
if ((*store)[index].guid == triggerFrom)
{ {
if (cache) (*store)[index].spawned = ReSpawn1Object(triggerFrom);
Despawn1Object(m_LastDespawnedNode); triggerFrom = 0;
Spawn1Object(roll); continue;
} }
else else
ReSpawn1Object(roll); (*store)[index].spawned = Spawn1Object((*store)[index].guid);
m_LastDespawnedNode = 0;
}
else if (limit < EqualChanced.size() && m_SpawnedPoolAmount < limit)
{
std::vector<uint32> IndexList;
for (size_t i = 0; i < EqualChanced.size(); ++i)
if (!EqualChanced[i].spawned)
IndexList.push_back(i);
while (m_SpawnedPoolAmount < limit && IndexList.size() > 0) if (triggerFrom)
{ {
uint32 roll = urand(1, IndexList.size()) - 1; // One spawn one despawn no count increase
uint32 index = IndexList[roll]; DespawnObject(triggerFrom);
if (!cache || (cache && EqualChanced[index].guid != m_LastDespawnedNode)) lastDespawned = triggerFrom;
{ triggerFrom = 0;
if (cache)
Despawn1Object(m_LastDespawnedNode);
EqualChanced[index].spawned = Spawn1Object(EqualChanced[index].guid);
} }
else else
EqualChanced[index].spawned = ReSpawn1Object(EqualChanced[index].guid); ++m_SpawnedPoolAmount;
if (EqualChanced[index].spawned)
++m_SpawnedPoolAmount; // limited group use the Spawned variable to store the number of actualy spawned creatures
std::vector<uint32>::iterator itr = IndexList.begin()+roll;
IndexList.erase(itr);
}
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);
} }
} }
@ -235,8 +243,7 @@ void PoolGroup<T>::SpawnObject(uint32 limit, bool cache)
template <> template <>
bool PoolGroup<Creature>::Spawn1Object(uint32 guid) bool PoolGroup<Creature>::Spawn1Object(uint32 guid)
{ {
CreatureData const* data = objmgr.GetCreatureData(guid); if (CreatureData const* data = objmgr.GetCreatureData(guid))
if (data)
{ {
objmgr.AddCreatureToGrid(guid, data); objmgr.AddCreatureToGrid(guid, data);
@ -250,12 +257,11 @@ bool PoolGroup<Creature>::Spawn1Object(uint32 guid)
if (!pCreature->LoadFromDB(guid, map)) if (!pCreature->LoadFromDB(guid, map))
{ {
delete pCreature; delete pCreature;
return false;
} }
else else
{
map->Add(pCreature); map->Add(pCreature);
} }
}
return true; return true;
} }
return false; return false;
@ -265,8 +271,7 @@ bool PoolGroup<Creature>::Spawn1Object(uint32 guid)
template <> template <>
bool PoolGroup<GameObject>::Spawn1Object(uint32 guid) bool PoolGroup<GameObject>::Spawn1Object(uint32 guid)
{ {
GameObjectData const* data = objmgr.GetGOData(guid); if (GameObjectData const* data = objmgr.GetGOData(guid))
if (data)
{ {
objmgr.AddGameobjectToGrid(guid, data); objmgr.AddGameobjectToGrid(guid, data);
// Spawn if necessary (loaded grids only) // Spawn if necessary (loaded grids only)
@ -280,6 +285,7 @@ bool PoolGroup<GameObject>::Spawn1Object(uint32 guid)
if (!pGameobject->LoadFromDB(guid, map)) if (!pGameobject->LoadFromDB(guid, map))
{ {
delete pGameobject; delete pGameobject;
return false;
} }
else else
{ {
@ -296,7 +302,9 @@ bool PoolGroup<GameObject>::Spawn1Object(uint32 guid)
template <> template <>
bool PoolGroup<Pool>::Spawn1Object(uint32 child_pool_id) bool PoolGroup<Pool>::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; return true;
} }
@ -304,8 +312,7 @@ bool PoolGroup<Pool>::Spawn1Object(uint32 child_pool_id)
template <> template <>
bool PoolGroup<Creature>::ReSpawn1Object(uint32 guid) bool PoolGroup<Creature>::ReSpawn1Object(uint32 guid)
{ {
CreatureData const* data = objmgr.GetCreatureData(guid); if (CreatureData const* data = objmgr.GetCreatureData(guid))
if (data)
{ {
if (Creature* pCreature = ObjectAccessor::Instance().GetObjectInWorld(MAKE_NEW_GUID(guid, data->id, HIGHGUID_UNIT), (Creature*)NULL)) if (Creature* pCreature = ObjectAccessor::Instance().GetObjectInWorld(MAKE_NEW_GUID(guid, data->id, HIGHGUID_UNIT), (Creature*)NULL))
pCreature->GetMap()->Add(pCreature); pCreature->GetMap()->Add(pCreature);
@ -318,8 +325,7 @@ bool PoolGroup<Creature>::ReSpawn1Object(uint32 guid)
template <> template <>
bool PoolGroup<GameObject>::ReSpawn1Object(uint32 guid) bool PoolGroup<GameObject>::ReSpawn1Object(uint32 guid)
{ {
GameObjectData const* data = objmgr.GetGOData(guid); if (GameObjectData const* data = objmgr.GetGOData(guid))
if (data)
{ {
if (GameObject* pGameobject = ObjectAccessor::Instance().GetObjectInWorld(MAKE_NEW_GUID(guid, data->id, HIGHGUID_GAMEOBJECT), (GameObject*)NULL)) if (GameObject* pGameobject = ObjectAccessor::Instance().GetObjectInWorld(MAKE_NEW_GUID(guid, data->id, HIGHGUID_GAMEOBJECT), (GameObject*)NULL))
pGameobject->GetMap()->Add(pGameobject); 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); 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; continue;
} }
SpawnPool(pool_entry); SpawnPool(pool_entry, 0, 0);
SpawnPool(pool_entry, 0, TYPEID_GAMEOBJECT);
SpawnPool(pool_entry, 0, TYPEID_UNIT);
count++; count++;
} while (result->NextRow()); } while (result->NextRow());
delete result; 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 // 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) // 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()) switch (type)
mPoolPoolGroups[pool_id].SpawnObject(mPoolTemplate[pool_id].MaxLimit, cache); {
if (!mPoolGameobjectGroups[pool_id].isEmpty()) case TYPEID_UNIT:
mPoolGameobjectGroups[pool_id].SpawnObject(mPoolTemplate[pool_id].MaxLimit, cache);
if (!mPoolCreatureGroups[pool_id].isEmpty()) if (!mPoolCreatureGroups[pool_id].isEmpty())
mPoolCreatureGroups[pool_id].SpawnObject(mPoolTemplate[pool_id].MaxLimit, cache); 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 // Call to despawn a pool, all gameobjects/creatures in this pool are removed
void PoolHandler::DespawnPool(uint16 pool_id) 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()) if (!mPoolCreatureGroups[pool_id].isEmpty())
mPoolCreatureGroups[pool_id].DespawnObject(); 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 // 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 // Then the spawn pool call will use this cache to decide
void PoolHandler::UpdatePool(uint16 pool_id, uint32 guid, uint32 type) void PoolHandler::UpdatePool(uint16 pool_id, uint32 guid, uint32 type)
{ {
uint16 motherpoolid = IsPartOfAPool(pool_id, 0); if (uint16 motherpoolid = IsPartOfAPool(pool_id, 0))
SpawnPool(motherpoolid, 0, 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);
else 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 // Method that tell if the gameobject/creature is part of a pool and return the pool id if yes

View file

@ -40,25 +40,24 @@ struct PoolObject
template <class T> template <class T>
class PoolGroup class PoolGroup
{ {
typedef std::vector<PoolObject> PoolObjectList;
public: public:
PoolGroup(); PoolGroup() : m_SpawnedPoolAmount(0) { }
~PoolGroup() {}; ~PoolGroup() {};
bool isEmpty() { return ExplicitlyChanced.empty() && EqualChanced.empty(); } bool isEmpty() { return ExplicitlyChanced.empty() && EqualChanced.empty(); }
void AddEntry(PoolObject& poolitem, uint32 maxentries); void AddEntry(PoolObject& poolitem, uint32 maxentries);
bool CheckPool(void); bool CheckPool(void);
uint32 RollOne(void); void RollOne(int32& index, PoolObjectList** store, uint32 triggerFrom);
bool IsSpawnedObject(uint32 guid); bool IsSpawnedObject(uint32 guid);
void DespawnObject(uint32 guid=0); void DespawnObject(uint32 guid=0);
void Despawn1Object(uint32 guid); void Despawn1Object(uint32 guid);
void SpawnObject(uint32 limit, bool cache=false); void SpawnObject(uint32 limit, uint32 triggerFrom);
bool Spawn1Object(uint32 guid); bool Spawn1Object(uint32 guid);
bool ReSpawn1Object(uint32 guid); bool ReSpawn1Object(uint32 guid);
void RemoveOneRelation(uint16 child_pool_id); void RemoveOneRelation(uint16 child_pool_id);
private: private:
typedef std::vector<PoolObject> PoolObjectList;
PoolObjectList ExplicitlyChanced; PoolObjectList ExplicitlyChanced;
PoolObjectList EqualChanced; 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 uint32 m_SpawnedPoolAmount; // Used to know the number of spawned objects
}; };
@ -75,7 +74,7 @@ class PoolHandler
uint16 IsPartOfAPool(uint32 guid, uint32 type); uint16 IsPartOfAPool(uint32 guid, uint32 type);
bool IsSpawnedObject(uint16 pool_id, uint32 guid, uint32 type); bool IsSpawnedObject(uint16 pool_id, uint32 guid, uint32 type);
bool CheckPool(uint16 pool_id); 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 DespawnPool(uint16 pool_id);
void UpdatePool(uint16 pool_id, uint32 guid, uint32 type); void UpdatePool(uint16 pool_id, uint32 guid, uint32 type);
void Initialize(); void Initialize();

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__ #ifndef __REVISION_NR_H__
#define __REVISION_NR_H__ #define __REVISION_NR_H__
#define REVISION_NR "8700" #define REVISION_NR "8701"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__