[9392] Update creature/gameobject pool at despawn instead spawn prepare.

This let solve problem with not despawned creature/gameobject at pool update in case when related grid not loaded.

Signed-off-by: VladimirMangos <vladimir@getmangos.com>
This commit is contained in:
Lynx3d 2010-02-15 21:15:57 +03:00 committed by VladimirMangos
parent 941b2edb10
commit b2718378ef
6 changed files with 93 additions and 41 deletions

View file

@ -374,10 +374,6 @@ void Creature::Update(uint32 diff)
//Call AI respawn virtual function //Call AI respawn virtual function
i_AI->JustRespawned(); i_AI->JustRespawned();
uint16 poolid = GetDBTableGUIDLow() ? sPoolMgr.IsPartOfAPool<Creature>(GetDBTableGUIDLow()) : 0;
if (poolid)
sPoolMgr.UpdatePool<Creature>(poolid, GetDBTableGUIDLow());
else
GetMap()->Add(this); GetMap()->Add(this);
} }
break; break;
@ -388,10 +384,18 @@ void Creature::Update(uint32 diff)
break; break;
if( m_deathTimer <= diff ) if( m_deathTimer <= diff )
{
// since pool system can fail to roll unspawned object, this one can remain spawned, so must set respawn nevertheless
uint16 poolid = GetDBTableGUIDLow() ? sPoolMgr.IsPartOfAPool<Creature>(GetDBTableGUIDLow()) : 0;
if (poolid)
sPoolMgr.UpdatePool<Creature>(poolid, GetDBTableGUIDLow());
if (IsInWorld()) // can be despawned by update pool
{ {
RemoveCorpse(); RemoveCorpse();
DEBUG_LOG("Removing corpse... %u ", GetEntry()); DEBUG_LOG("Removing corpse... %u ", GetEntry());
} }
}
else else
{ {
m_deathTimer -= diff; m_deathTimer -= diff;
@ -418,10 +422,21 @@ void Creature::Update(uint32 diff)
if (m_isDeadByDefault) if (m_isDeadByDefault)
{ {
if( m_deathTimer <= diff ) if( m_deathTimer <= diff )
{
// since pool system can fail to roll unspawned object, this one can remain spawned, so must set respawn nevertheless
uint16 poolid = GetDBTableGUIDLow() ? sPoolMgr.IsPartOfAPool<Creature>(GetDBTableGUIDLow()) : 0;
if (poolid)
sPoolMgr.UpdatePool<Creature>(poolid, GetDBTableGUIDLow());
if (IsInWorld()) // can be despawned by update pool
{ {
RemoveCorpse(); RemoveCorpse();
DEBUG_LOG("Removing alive corpse... %u ", GetEntry()); DEBUG_LOG("Removing alive corpse... %u ", GetEntry());
} }
else
return;
}
else else
{ {
m_deathTimer -= diff; m_deathTimer -= diff;

View file

@ -574,7 +574,7 @@ 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)
sPoolMgr.SpawnPool(*itr); sPoolMgr.SpawnPool(*itr, true);
} }
void GameEventMgr::GameEventUnspawn(int16 event_id) void GameEventMgr::GameEventUnspawn(int16 event_id)

View file

@ -256,10 +256,6 @@ void GameObject::Update(uint32 /*p_time*/)
return; return;
} }
// respawn timer // respawn timer
uint16 poolid = GetDBTableGUIDLow() ? sPoolMgr.IsPartOfAPool<GameObject>(GetDBTableGUIDLow()) : 0;
if (poolid)
sPoolMgr.UpdatePool<GameObject>(poolid, GetDBTableGUIDLow());
else
GetMap()->Add(this); GetMap()->Add(this);
break; break;
} }
@ -445,12 +441,19 @@ void GameObject::Update(uint32 /*p_time*/)
return; return;
} }
// since pool system can fail to roll unspawned object, this one can remain spawned, so must set respawn nevertheless
m_respawnTime = time(NULL) + m_respawnDelayTime; m_respawnTime = time(NULL) + m_respawnDelayTime;
// if option not set then object will be saved at grid unload // if option not set then object will be saved at grid unload
if(sWorld.getConfig(CONFIG_BOOL_SAVE_RESPAWN_TIME_IMMEDIATLY)) if(sWorld.getConfig(CONFIG_BOOL_SAVE_RESPAWN_TIME_IMMEDIATLY))
SaveRespawnTime(); SaveRespawnTime();
// if part of pool, let pool system schedule new spawn instead of just scheduling respawn
if(uint16 poolid = GetDBTableGUIDLow() ? sPoolMgr.IsPartOfAPool<GameObject>(GetDBTableGUIDLow()) : 0)
sPoolMgr.UpdatePool<GameObject>(poolid, GetDBTableGUIDLow());
// can be not in world at pool despawn
if (IsInWorld())
UpdateObjectVisibility(); UpdateObjectVisibility();
break; break;

View file

@ -22,6 +22,7 @@
#include "ProgressBar.h" #include "ProgressBar.h"
#include "Log.h" #include "Log.h"
#include "MapManager.h" #include "MapManager.h"
#include "World.h"
#include "Policies/SingletonImp.h" #include "Policies/SingletonImp.h"
INSTANTIATE_SINGLETON_1(PoolManager); INSTANTIATE_SINGLETON_1(PoolManager);
@ -253,7 +254,7 @@ void PoolGroup<Pool>::RemoveOneRelation(uint16 child_pool_id)
} }
template <class T> template <class T>
void PoolGroup<T>::SpawnObject(SpawnedPoolData& spawns, uint32 limit, uint32 triggerFrom) void PoolGroup<T>::SpawnObject(SpawnedPoolData& spawns, uint32 limit, uint32 triggerFrom, bool instantly)
{ {
uint32 lastDespawned = 0; uint32 lastDespawned = 0;
int count = limit - spawns.GetSpawnedObjects(poolId); int count = limit - spawns.GetSpawnedObjects(poolId);
@ -283,7 +284,7 @@ void PoolGroup<T>::SpawnObject(SpawnedPoolData& spawns, uint32 limit, uint32 tri
} }
spawns.AddSpawn<T>(obj->guid,poolId); spawns.AddSpawn<T>(obj->guid,poolId);
Spawn1Object(obj); Spawn1Object(obj, instantly);
if (triggerFrom) if (triggerFrom)
{ {
@ -297,7 +298,7 @@ void PoolGroup<T>::SpawnObject(SpawnedPoolData& spawns, uint32 limit, uint32 tri
// Method that is actualy doing the spawn job on 1 creature // Method that is actualy doing the spawn job on 1 creature
template <> template <>
void PoolGroup<Creature>::Spawn1Object(PoolObject* obj) void PoolGroup<Creature>::Spawn1Object(PoolObject* obj, bool instantly)
{ {
if (CreatureData const* data = sObjectMgr.GetCreatureData(obj->guid)) if (CreatureData const* data = sObjectMgr.GetCreatureData(obj->guid))
{ {
@ -305,7 +306,7 @@ void PoolGroup<Creature>::Spawn1Object(PoolObject* obj)
// Spawn if necessary (loaded grids only) // Spawn if necessary (loaded grids only)
Map* map = const_cast<Map*>(sMapMgr.CreateBaseMap(data->mapid)); Map* map = const_cast<Map*>(sMapMgr.CreateBaseMap(data->mapid));
// We use spawn coords to spawn // We use spawn coords to spawn (avoid work for instances until implemented support)
if (!map->Instanceable() && map->IsLoaded(data->posX, data->posY)) if (!map->Instanceable() && map->IsLoaded(data->posX, data->posY))
{ {
Creature* pCreature = new Creature; Creature* pCreature = new Creature;
@ -316,14 +317,28 @@ void PoolGroup<Creature>::Spawn1Object(PoolObject* obj)
return; return;
} }
else else
{
// if new spawn replaces a just despawned creature, not instantly spawn but set respawn timer
if(!instantly)
{
pCreature->SetRespawnTime( pCreature->GetRespawnDelay() );
if (sWorld.getConfig(CONFIG_SAVE_RESPAWN_TIME_IMMEDIATLY) || pCreature->isWorldBoss())
pCreature->SaveRespawnTime();
}
map->Add(pCreature); map->Add(pCreature);
} }
} }
// for not loaded grid just update respawn time (avoid work for instances until implemented support)
else if(!map->Instanceable() && !instantly)
{
sObjectMgr.SaveCreatureRespawnTime(obj->guid,map->GetInstanceId(),time(NULL) + data->spawntimesecs);
}
}
} }
// Same for 1 gameobject // Same for 1 gameobject
template <> template <>
void PoolGroup<GameObject>::Spawn1Object(PoolObject* obj) void PoolGroup<GameObject>::Spawn1Object(PoolObject* obj, bool instantly)
{ {
if (GameObjectData const* data = sObjectMgr.GetGOData(obj->guid)) if (GameObjectData const* data = sObjectMgr.GetGOData(obj->guid))
{ {
@ -332,6 +347,7 @@ void PoolGroup<GameObject>::Spawn1Object(PoolObject* obj)
// this base map checked as non-instanced and then only existed // this base map checked as non-instanced and then only existed
Map* map = const_cast<Map*>(sMapMgr.CreateBaseMap(data->mapid)); Map* map = const_cast<Map*>(sMapMgr.CreateBaseMap(data->mapid));
// We use current coords to unspawn, not spawn coords since creature can have changed grid // We use current coords to unspawn, not spawn coords since creature can have changed grid
// (avoid work for instances until implemented support)
if (!map->Instanceable() && map->IsLoaded(data->posX, data->posY)) if (!map->Instanceable() && map->IsLoaded(data->posX, data->posY))
{ {
GameObject* pGameobject = new GameObject; GameObject* pGameobject = new GameObject;
@ -344,17 +360,33 @@ void PoolGroup<GameObject>::Spawn1Object(PoolObject* obj)
else else
{ {
if (pGameobject->isSpawnedByDefault()) if (pGameobject->isSpawnedByDefault())
{
// if new spawn replaces a just despawned object, not instantly spawn but set respawn timer
if(!instantly)
{
pGameobject->SetRespawnTime( pGameobject->GetRespawnDelay() );
if (sWorld.getConfig(CONFIG_SAVE_RESPAWN_TIME_IMMEDIATLY))
pGameobject->SaveRespawnTime();
}
map->Add(pGameobject); map->Add(pGameobject);
} }
} }
} }
// for not loaded grid just update respawn time (avoid work for instances until implemented support)
else if(!map->Instanceable() && !instantly)
{
// for spawned by default object only
if (data->spawntimesecs >= 0)
sObjectMgr.SaveGORespawnTime(obj->guid,map->GetInstanceId(),time(NULL) + data->spawntimesecs);
}
}
} }
// Same for 1 pool // Same for 1 pool
template <> template <>
void PoolGroup<Pool>::Spawn1Object(PoolObject* obj) void PoolGroup<Pool>::Spawn1Object(PoolObject* obj, bool instantly)
{ {
sPoolMgr.SpawnPool(obj->guid); sPoolMgr.SpawnPool(obj->guid, instantly);
} }
// Method that does the respawn job on the specified creature // Method that does the respawn job on the specified creature
@ -676,7 +708,7 @@ void PoolManager::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, true);
count++; count++;
} while (result->NextRow()); } while (result->NextRow());
delete result; delete result;
@ -688,35 +720,37 @@ void PoolManager::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 creature is respawned only (added back to map) // If it's same, the creature is respawned only (added back to map)
template<> template<>
void PoolManager::SpawnPool<Creature>(uint16 pool_id, uint32 db_guid) void PoolManager::SpawnPoolGroup<Creature>(uint16 pool_id, uint32 db_guid, bool instantly)
{ {
if (!mPoolCreatureGroups[pool_id].isEmpty()) if (!mPoolCreatureGroups[pool_id].isEmpty())
mPoolCreatureGroups[pool_id].SpawnObject(mSpawnedData, mPoolTemplate[pool_id].MaxLimit, db_guid); mPoolCreatureGroups[pool_id].SpawnObject(mSpawnedData, mPoolTemplate[pool_id].MaxLimit, db_guid, instantly);
} }
// 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 is respawned only (added back to map) // If it's same, the gameobject is respawned only (added back to map)
template<> template<>
void PoolManager::SpawnPool<GameObject>(uint16 pool_id, uint32 db_guid) void PoolManager::SpawnPoolGroup<GameObject>(uint16 pool_id, uint32 db_guid, bool instantly)
{ {
if (!mPoolGameobjectGroups[pool_id].isEmpty()) if (!mPoolGameobjectGroups[pool_id].isEmpty())
mPoolGameobjectGroups[pool_id].SpawnObject(mSpawnedData, mPoolTemplate[pool_id].MaxLimit, db_guid); mPoolGameobjectGroups[pool_id].SpawnObject(mSpawnedData, mPoolTemplate[pool_id].MaxLimit, db_guid, instantly);
} }
// 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 pool is respawned only // If it's same, the pool is respawned only
template<> template<>
void PoolManager::SpawnPool<Pool>(uint16 pool_id, uint32 sub_pool_id) void PoolManager::SpawnPoolGroup<Pool>(uint16 pool_id, uint32 sub_pool_id, bool instantly)
{ {
if (!mPoolPoolGroups[pool_id].isEmpty()) if (!mPoolPoolGroups[pool_id].isEmpty())
mPoolPoolGroups[pool_id].SpawnObject(mSpawnedData, mPoolTemplate[pool_id].MaxLimit, sub_pool_id); mPoolPoolGroups[pool_id].SpawnObject(mSpawnedData, mPoolTemplate[pool_id].MaxLimit, sub_pool_id, instantly);
} }
void PoolManager::SpawnPool( uint16 pool_id ) /*!
\param instantly defines if (leaf-)objects are spawned instantly or with fresh respawn timer */
void PoolManager::SpawnPool(uint16 pool_id, bool instantly)
{ {
SpawnPool<Pool>(pool_id, 0); SpawnPoolGroup<Pool>(pool_id, 0, instantly);
SpawnPool<GameObject>(pool_id, 0); SpawnPoolGroup<GameObject>(pool_id, 0, instantly);
SpawnPool<Creature>(pool_id, 0); SpawnPoolGroup<Creature>(pool_id, 0, instantly);
} }
// 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
@ -748,9 +782,9 @@ template<typename T>
void PoolManager::UpdatePool(uint16 pool_id, uint32 db_guid_or_pool_id) void PoolManager::UpdatePool(uint16 pool_id, uint32 db_guid_or_pool_id)
{ {
if (uint16 motherpoolid = IsPartOfAPool<Pool>(pool_id)) if (uint16 motherpoolid = IsPartOfAPool<Pool>(pool_id))
SpawnPool<Pool>(motherpoolid, pool_id); SpawnPoolGroup<Pool>(motherpoolid, pool_id, false);
else else
SpawnPool<T>(pool_id, db_guid_or_pool_id); SpawnPoolGroup<T>(pool_id, db_guid_or_pool_id, false);
} }
template void PoolManager::UpdatePool<Pool>(uint16 pool_id, uint32 db_guid_or_pool_id); template void PoolManager::UpdatePool<Pool>(uint16 pool_id, uint32 db_guid_or_pool_id);

View file

@ -76,9 +76,9 @@ class PoolGroup
PoolObject* RollOne(SpawnedPoolData& spawns, uint32 triggerFrom); PoolObject* RollOne(SpawnedPoolData& spawns, uint32 triggerFrom);
void DespawnObject(SpawnedPoolData& spawns, uint32 guid=0); void DespawnObject(SpawnedPoolData& spawns, uint32 guid=0);
void Despawn1Object(uint32 guid); void Despawn1Object(uint32 guid);
void SpawnObject(SpawnedPoolData& spawns, uint32 limit, uint32 triggerFrom); void SpawnObject(SpawnedPoolData& spawns, uint32 limit, uint32 triggerFrom, bool instantly);
void Spawn1Object(PoolObject* obj); void Spawn1Object(PoolObject* obj, bool instantly);
void ReSpawn1Object(PoolObject* obj); void ReSpawn1Object(PoolObject* obj);
void RemoveOneRelation(uint16 child_pool_id); void RemoveOneRelation(uint16 child_pool_id);
private: private:
@ -104,7 +104,7 @@ class PoolManager
bool CheckPool(uint16 pool_id) const; bool CheckPool(uint16 pool_id) const;
void SpawnPool(uint16 pool_id); void SpawnPool(uint16 pool_id, bool instantly);
void DespawnPool(uint16 pool_id); void DespawnPool(uint16 pool_id);
template<typename T> template<typename T>
@ -112,7 +112,7 @@ class PoolManager
protected: protected:
template<typename T> template<typename T>
void SpawnPool(uint16 pool_id, uint32 db_guid_or_pool_id); void SpawnPoolGroup(uint16 pool_id, uint32 db_guid_or_pool_id, bool instantly);
uint16 max_pool_id; uint16 max_pool_id;
typedef std::vector<PoolTemplateData> PoolTemplateDataMap; typedef std::vector<PoolTemplateData> PoolTemplateDataMap;

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 "9391" #define REVISION_NR "9392"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__