Core/Maps: move pooling hand-off outside of Map::CheckRespawn (PR#25785)

fixes #25777
This commit is contained in:
Treeston
2020-12-30 21:08:22 +01:00
committed by GitHub
parent 0ad1854d1c
commit f8afcec9f3
3 changed files with 69 additions and 56 deletions

View File

@@ -3036,47 +3036,42 @@ bool Map::CheckRespawn(RespawnInfo* info)
return false;
}
uint32 poolId = info->spawnId ? sPoolMgr->IsPartOfAPool(info->type, info->spawnId) : 0;
// Next, check if there's already an instance of this object that would block the respawn
// Only do this for unpooled spawns
if (!poolId)
bool alreadyExists = false;
switch (info->type)
{
bool doDelete = false;
switch (info->type)
case SPAWN_TYPE_CREATURE:
{
case SPAWN_TYPE_CREATURE:
{
// escort check for creatures only (if the world config boolean is set)
bool const isEscort = (sWorld->getBoolConfig(CONFIG_RESPAWN_DYNAMIC_ESCORTNPC) && data->spawnGroupData->flags & SPAWNGROUP_FLAG_ESCORTQUESTNPC);
// escort check for creatures only (if the world config boolean is set)
bool const isEscort = (sWorld->getBoolConfig(CONFIG_RESPAWN_DYNAMIC_ESCORTNPC) && data->spawnGroupData->flags & SPAWNGROUP_FLAG_ESCORTQUESTNPC);
auto range = _creatureBySpawnIdStore.equal_range(info->spawnId);
for (auto it = range.first; it != range.second; ++it)
{
Creature* creature = it->second;
if (!creature->IsAlive())
continue;
// escort NPCs are allowed to respawn as long as all other instances are already escorting
if (isEscort && creature->IsEscorted())
continue;
doDelete = true;
break;
}
auto range = _creatureBySpawnIdStore.equal_range(info->spawnId);
for (auto it = range.first; it != range.second; ++it)
{
Creature* creature = it->second;
if (!creature->IsAlive())
continue;
// escort NPCs are allowed to respawn as long as all other instances are already escorting
if (isEscort && creature->IsEscorted())
continue;
alreadyExists = true;
break;
}
case SPAWN_TYPE_GAMEOBJECT:
// gameobject check is simpler - they cannot be dead or escorting
if (_gameobjectBySpawnIdStore.find(info->spawnId) != _gameobjectBySpawnIdStore.end())
doDelete = true;
break;
default:
ABORT_MSG("Invalid spawn type %u with spawnId %u on map %u", uint32(info->type), info->spawnId, GetId());
return true;
}
if (doDelete)
{
info->respawnTime = 0;
return false;
break;
}
case SPAWN_TYPE_GAMEOBJECT:
// gameobject check is simpler - they cannot be dead or escorting
if (_gameobjectBySpawnIdStore.find(info->spawnId) != _gameobjectBySpawnIdStore.end())
alreadyExists = true;
break;
default:
ABORT_MSG("Invalid spawn type %u with spawnId %u on map %u", uint32(info->type), info->spawnId, GetId());
return true;
}
if (alreadyExists)
{
info->respawnTime = 0;
return false;
}
// next, check linked respawn time
@@ -3094,21 +3089,6 @@ bool Map::CheckRespawn(RespawnInfo* info)
info->respawnTime = respawnTime;
return false;
}
// now, check if we're part of a pool
if (poolId)
{
// ok, part of a pool - hand off to pool logic to handle this, we're just going to remove the respawn and call it a day
if (info->type == SPAWN_TYPE_GAMEOBJECT)
sPoolMgr->UpdatePool<GameObject>(poolId, info->spawnId);
else if (info->type == SPAWN_TYPE_CREATURE)
sPoolMgr->UpdatePool<Creature>(poolId, info->spawnId);
else
ABORT_MSG("Invalid spawn type %u (spawnid %u) on map %u", uint32(info->type), info->spawnId, GetId());
info->respawnTime = 0;
return false;
}
// everything ok, let's spawn
return true;
}
@@ -3275,22 +3255,39 @@ void Map::ProcessRespawns()
RespawnInfo* next = _respawnTimes.top();
if (now < next->respawnTime) // done for this tick
break;
if (CheckRespawn(next)) // see if we're allowed to respawn
{
// ok, respawn
if (uint32 poolId = sPoolMgr->IsPartOfAPool(next->type, next->spawnId)) // is this part of a pool?
{ // if yes, respawn will be handled by (external) pooling logic, just delete the respawn time
// step 1: remove entry from maps to avoid it being reachable by outside logic
_respawnTimes.pop();
GetRespawnMapForType(next->type).erase(next->spawnId);
// step 2: tell pooling logic to do its thing
sPoolMgr->UpdatePool(poolId, next->type, next->spawnId);
// step 3: get rid of the actual entry
delete next;
}
else if (CheckRespawn(next)) // see if we're allowed to respawn
{ // ok, respawn
// step 1: remove entry from maps to avoid it being reachable by outside logic
_respawnTimes.pop();
GetRespawnMapForType(next->type).erase(next->spawnId);
// step 2: do the respawn, which involves external logic
DoRespawn(next->type, next->spawnId, next->gridId);
// step 3: get rid of the actual entry
delete next;
}
else if (!next->respawnTime) // just remove respawn entry without rescheduling
{
else if (!next->respawnTime)
{ // just remove this respawn entry without rescheduling
_respawnTimes.pop();
GetRespawnMapForType(next->type).erase(next->spawnId);
delete next;
}
else // value changed, update heap position
{
else
{ // new respawn time, update heap position
ASSERT(now < next->respawnTime); // infinite loop guard
_respawnTimes.decrease(next->handle);
SaveRespawnInfoDB(*next);

View File

@@ -845,3 +845,18 @@ void PoolMgr::UpdatePool(uint32 pool_id, uint32 db_guid_or_pool_id)
template void PoolMgr::UpdatePool<Pool>(uint32 pool_id, uint32 db_guid_or_pool_id);
template void PoolMgr::UpdatePool<GameObject>(uint32 pool_id, uint32 db_guid_or_pool_id);
template void PoolMgr::UpdatePool<Creature>(uint32 pool_id, uint32 db_guid_or_pool_id);
void PoolMgr::UpdatePool(uint32 pool_id, SpawnObjectType type, uint32 spawnId)
{
switch (type)
{
case SPAWN_TYPE_CREATURE:
UpdatePool<Creature>(pool_id, spawnId);
break;
case SPAWN_TYPE_GAMEOBJECT:
UpdatePool<GameObject>(pool_id, spawnId);
break;
default:
ABORT_MSG("Invalid spawn type %u passed to PoolMgr::IsPartOfPool (with spawnId %u)", uint32(type), spawnId);
}
}

View File

@@ -120,6 +120,7 @@ class TC_GAME_API PoolMgr
template<typename T>
void UpdatePool(uint32 pool_id, uint32 db_guid_or_pool_id);
void UpdatePool(uint32 pool_id, SpawnObjectType type, ObjectGuid::LowType spawnId);
private:
template<typename T>