From d83cd33bd46a8716b1d0ceee565395f9a38718a3 Mon Sep 17 00:00:00 2001 From: Giacomo Pozzoni Date: Sat, 26 Jun 2021 14:21:18 +0200 Subject: [PATCH] Core/Pools: Fix pools with 1 member never spawning anything anymore (#26620) * Core/Pools: Fix pools with 1 member never spawning anything anymore Attempts to fix a 6 years old bug and never fixed by the original author. * Remove respawn times from db once a respawn has been handled * Allow to specify if Despawn1Object() should save or not the respawn time. We don't need to do that when respawning an object. * Apply the same fix to GameObjects too # Conflicts: # src/server/game/Pools/PoolMgr.h --- .../game/Entities/Creature/Creature.cpp | 7 +++-- src/server/game/Maps/Map.cpp | 3 +++ src/server/game/Pools/PoolMgr.cpp | 26 ++++++++++--------- src/server/game/Pools/PoolMgr.h | 8 +++--- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index ede85fed35..21ed88edf1 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -1671,9 +1671,12 @@ bool Creature::LoadFromDB(ObjectGuid::LowType spawnId, Map* map, bool addToMap, return false; } } + else + { + // compatibility mode creatures will be respawned in ::Update() + m_deathState = DEAD; + } - // compatibility mode creatures will be respawned in ::Update() - m_deathState = DEAD; if (CanFly()) { float tz = map->GetHeight(GetPhaseShift(), data->spawnPoint, true, MAX_FALL_DISTANCE); diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 8d34e51261..46e16c3ada 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -3226,6 +3226,7 @@ void Map::ProcessRespawns() sPoolMgr->UpdatePool(poolId, next->type, next->spawnId); // step 3: get rid of the actual entry + RemoveRespawnTime(next->type, next->spawnId, nullptr, true); delete next; } else if (CheckRespawn(next)) // see if we're allowed to respawn @@ -3238,12 +3239,14 @@ void Map::ProcessRespawns() DoRespawn(next->type, next->spawnId, next->gridId); // step 3: get rid of the actual entry + RemoveRespawnTime(next->type, next->spawnId, nullptr, true); delete next; } else if (!next->respawnTime) { // just remove this respawn entry without rescheduling _respawnTimes.pop(); GetRespawnMapForType(next->type).erase(next->spawnId); + RemoveRespawnTime(next->type, next->spawnId, nullptr, true); delete next; } else diff --git a/src/server/game/Pools/PoolMgr.cpp b/src/server/game/Pools/PoolMgr.cpp index 1d27921ec7..dbec6b0231 100644 --- a/src/server/game/Pools/PoolMgr.cpp +++ b/src/server/game/Pools/PoolMgr.cpp @@ -169,7 +169,7 @@ void PoolGroup::DespawnObject(ActivePoolData& spawns, ObjectGuid::LowType gui // Method that is actualy doing the removal job on one creature template<> -void PoolGroup::Despawn1Object(ObjectGuid::LowType guid, bool alwaysDeleteRespawnTime) +void PoolGroup::Despawn1Object(ObjectGuid::LowType guid, bool alwaysDeleteRespawnTime, bool saveRespawnTime) { if (CreatureData const* data = sObjectMgr->GetCreatureData(guid)) { @@ -184,7 +184,7 @@ void PoolGroup::Despawn1Object(ObjectGuid::LowType guid, bool alwaysDe Creature* creature = itr->second; ++itr; // For dynamic spawns, save respawn time here - if (!creature->GetRespawnCompatibilityMode()) + if (saveRespawnTime && !creature->GetRespawnCompatibilityMode()) creature->SaveRespawnTime(); creature->AddObjectToRemoveList(); } @@ -196,7 +196,7 @@ void PoolGroup::Despawn1Object(ObjectGuid::LowType guid, bool alwaysDe // Same on one gameobject template<> -void PoolGroup::Despawn1Object(ObjectGuid::LowType guid, bool alwaysDeleteRespawnTime) +void PoolGroup::Despawn1Object(ObjectGuid::LowType guid, bool alwaysDeleteRespawnTime, bool saveRespawnTime) { if (GameObjectData const* data = sObjectMgr->GetGameObjectData(guid)) { @@ -212,7 +212,7 @@ void PoolGroup::Despawn1Object(ObjectGuid::LowType guid, bool always ++itr; // For dynamic spawns, save respawn time here - if (!go->GetRespawnCompatibilityMode()) + if (saveRespawnTime && !go->GetRespawnCompatibilityMode()) go->SaveRespawnTime(); go->AddObjectToRemoveList(); } @@ -224,7 +224,7 @@ void PoolGroup::Despawn1Object(ObjectGuid::LowType guid, bool always // Same on one pool template<> -void PoolGroup::Despawn1Object(uint32 child_pool_id, bool alwaysDeleteRespawnTime) +void PoolGroup::Despawn1Object(uint32 child_pool_id, bool alwaysDeleteRespawnTime, bool /*saveRespawnTime*/) { sPoolMgr->DespawnPool(child_pool_id, alwaysDeleteRespawnTime); } @@ -277,7 +277,7 @@ void PoolGroup::SpawnObject(ActivePoolData& spawns, uint32 limit, uint32 trig roll -= obj.chance; // 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 (roll < 0 && (/*obj.guid == triggerFrom ||*/ !spawns.IsActiveObject(obj.guid))) + if (roll < 0 && (obj.guid == triggerFrom || !spawns.IsActiveObject(obj.guid))) { rolledObjects.push_back(obj); break; @@ -287,9 +287,9 @@ void PoolGroup::SpawnObject(ActivePoolData& spawns, uint32 limit, uint32 trig if (!EqualChanced.empty() && rolledObjects.empty()) { - std::copy_if(EqualChanced.begin(), EqualChanced.end(), std::back_inserter(rolledObjects), [/*triggerFrom, */&spawns](PoolObject const& object) + std::copy_if(EqualChanced.begin(), EqualChanced.end(), std::back_inserter(rolledObjects), [triggerFrom, &spawns](PoolObject const& object) { - return /*object.guid == triggerFrom ||*/ !spawns.IsActiveObject(object.guid); + return object.guid == triggerFrom || !spawns.IsActiveObject(object.guid); }); Trinity::Containers::RandomResize(rolledObjects, count); @@ -381,16 +381,18 @@ void PoolGroup::Spawn1Object(PoolObject* obj) // Method that does the respawn job on the specified creature template <> -void PoolGroup::ReSpawn1Object(PoolObject* /*obj*/) +void PoolGroup::ReSpawn1Object(PoolObject* obj) { - // Creature is still on map, nothing to do + Despawn1Object(obj->guid, false, false); + Spawn1Object(obj); } // Method that does the respawn job on the specified gameobject template <> -void PoolGroup::ReSpawn1Object(PoolObject* /*obj*/) +void PoolGroup::ReSpawn1Object(PoolObject* obj) { - // GameObject is still on map, nothing to do + Despawn1Object(obj->guid, false, false); + Spawn1Object(obj); } // Nothing to do for a child Pool diff --git a/src/server/game/Pools/PoolMgr.h b/src/server/game/Pools/PoolMgr.h index b8cf9e159f..36bcad0d60 100644 --- a/src/server/game/Pools/PoolMgr.h +++ b/src/server/game/Pools/PoolMgr.h @@ -25,13 +25,13 @@ struct PoolTemplateData { - uint32 MaxLimit; + uint32 MaxLimit; }; struct PoolObject { - ObjectGuid::LowType guid; - float chance; + ObjectGuid::LowType guid; + float chance; PoolObject(ObjectGuid::LowType _guid, float _chance) : guid(_guid), chance(std::fabs(_chance)) { } }; @@ -73,7 +73,7 @@ class TC_GAME_API PoolGroup void AddEntry(PoolObject& poolitem, uint32 maxentries); bool CheckPool() const; void DespawnObject(ActivePoolData& spawns, ObjectGuid::LowType guid = 0, bool alwaysDeleteRespawnTime = false); - void Despawn1Object(ObjectGuid::LowType guid, bool alwaysDeleteRespawnTime = false); + void Despawn1Object(ObjectGuid::LowType guid, bool alwaysDeleteRespawnTime = false, bool saveRespawnTime = true); void SpawnObject(ActivePoolData& spawns, uint32 limit, uint32 triggerFrom); void RemoveRespawnTimeFromDB(ObjectGuid::LowType guid);