27#include <fmt/ranges.h>
42 SpawnedPoolPools::const_iterator itr =
mSpawnedPools.find(pool_id);
72 return IsSpawnedObject<Creature>(db_guid_or_pool_id);
74 return IsSpawnedObject<GameObject>(db_guid_or_pool_id);
76 ABORT_MSG(
"Invalid spawn type %u passed to SpawnedPoolData::IsSpawnedObject (with spawnId " UI64FMTD ")",
uint32(type), db_guid_or_pool_id);
81void SpawnedPoolData::AddSpawn<Creature>(
uint64 db_guid,
uint32 pool_id)
88void SpawnedPoolData::AddSpawn<GameObject>(
uint64 db_guid,
uint32 pool_id)
95void SpawnedPoolData::AddSpawn<Pool>(
uint64 sub_pool_id,
uint32 pool_id)
102void SpawnedPoolData::RemoveSpawn<Creature>(
uint64 db_guid,
uint32 pool_id)
111void SpawnedPoolData::RemoveSpawn<GameObject>(
uint64 db_guid,
uint32 pool_id)
120void SpawnedPoolData::RemoveSpawn<Pool>(
uint64 sub_pool_id,
uint32 pool_id)
148 for (
PoolObject const& explicitlyChanced : ExplicitlyChanced)
149 if (!
sPoolMgr->IsEmpty(explicitlyChanced.guid))
152 for (
PoolObject const& equalChanced : EqualChanced)
153 if (!
sPoolMgr->IsEmpty(equalChanced.guid))
163 if (poolitem.
chance != 0 && maxentries == 1)
164 ExplicitlyChanced.push_back(poolitem);
166 EqualChanced.push_back(poolitem);
173 if (EqualChanced.empty())
176 for (
uint32 i = 0; i < ExplicitlyChanced.size(); ++i)
177 chance += ExplicitlyChanced[i].chance;
178 if (chance != 100 && chance != 0)
190 for (
size_t i=0; i < EqualChanced.size(); ++i)
195 if (!guid || EqualChanced[i].guid == guid)
197 Despawn1Object(spawns, EqualChanced[i].guid, alwaysDeleteRespawnTime);
198 spawns.
RemoveSpawn<T>(EqualChanced[i].guid, poolId);
201 else if (alwaysDeleteRespawnTime)
202 RemoveRespawnTimeFromDB(spawns, EqualChanced[i].guid);
205 for (
size_t i = 0; i < ExplicitlyChanced.size(); ++i)
210 if (!guid || ExplicitlyChanced[i].guid == guid)
212 Despawn1Object(spawns, ExplicitlyChanced[i].guid, alwaysDeleteRespawnTime);
213 spawns.
RemoveSpawn<T>(ExplicitlyChanced[i].guid, poolId);
216 else if (alwaysDeleteRespawnTime)
217 RemoveRespawnTimeFromDB(spawns, ExplicitlyChanced[i].guid);
226 for (
auto itr = creatureBounds.first; itr != creatureBounds.second;)
236 if (alwaysDeleteRespawnTime)
245 for (
auto itr = gameobjectBounds.first; itr != gameobjectBounds.second;)
256 if (alwaysDeleteRespawnTime)
264 sPoolMgr->DespawnPool(spawns, child_pool_id, alwaysDeleteRespawnTime);
271 for (PoolObjectList::iterator itr = ExplicitlyChanced.begin(); itr != ExplicitlyChanced.end(); ++itr)
273 if (itr->guid == child_pool_id)
275 ExplicitlyChanced.erase(itr);
279 for (PoolObjectList::iterator itr = EqualChanced.begin(); itr != EqualChanced.end(); ++itr)
281 if (itr->guid == child_pool_id)
283 EqualChanced.erase(itr);
303 rolledObjects.reserve(count);
306 if (!ExplicitlyChanced.empty())
315 if (roll < 0 && (obj.guid == triggerFrom || !spawns.
IsSpawnedObject<T>(obj.guid)))
317 rolledObjects.push_back(obj);
323 if (!EqualChanced.empty() && rolledObjects.empty())
325 std::copy_if(EqualChanced.begin(), EqualChanced.end(), std::back_inserter(rolledObjects), [triggerFrom, &spawns](
PoolObject const&
object)
327 return object.guid == triggerFrom || !spawns.IsSpawnedObject<T>(object.guid);
336 if (obj.guid == triggerFrom)
338 ReSpawn1Object(spawns, &obj);
343 spawns.
AddSpawn<T>(obj.guid, poolId);
344 Spawn1Object(spawns, &obj);
351 DespawnObject(spawns, triggerFrom);
394 Despawn1Object(spawns, obj->
guid,
false,
false);
395 Spawn1Object(spawns, obj);
402 Despawn1Object(spawns, obj->
guid,
false,
false);
403 Spawn1Object(spawns, obj);
453 TC_LOG_INFO(
"server.loading",
">> Loaded 0 object pools. DB table `pool_template` is empty.");
460 Field* fields = result->Fetch();
466 pPoolTemplate.
MapId = -1;
470 while (result->NextRow());
477 TC_LOG_INFO(
"server.loading",
"Loading Creatures Pooling Data...");
486 TC_LOG_INFO(
"server.loading",
">> Loaded 0 creatures in pools. DB table `pool_creature` is empty.");
493 Field* fields = result->Fetch();
497 float chance = fields[2].
GetFloat();
502 TC_LOG_ERROR(
"sql.sql",
"`pool_creature` has a non existing creature spawn (GUID: {}) defined for pool id ({}), skipped.", guid, pool_id);
508 TC_LOG_ERROR(
"sql.sql",
"`pool_creature` pool id ({}) is not in `pool_template`, skipped.", pool_id);
511 if (chance < 0 || chance > 100)
513 TC_LOG_ERROR(
"sql.sql",
"`pool_creature` has an invalid chance ({}) for creature guid ({}) in pool id ({}), skipped.", chance, guid, pool_id);
517 if (pPoolTemplate->
MapId == -1)
522 TC_LOG_ERROR(
"sql.sql",
"`pool_creature` has creature spawns on multiple different maps for creature guid ({}) in pool id ({}), skipped.", guid, pool_id);
535 while (result->NextRow());
543 TC_LOG_INFO(
"server.loading",
"Loading Gameobject Pooling Data...");
552 TC_LOG_INFO(
"server.loading",
">> Loaded 0 gameobjects in pools. DB table `pool_gameobject` is empty.");
559 Field* fields = result->Fetch();
563 float chance = fields[2].
GetFloat();
568 TC_LOG_ERROR(
"sql.sql",
"`pool_gameobject` has a non existing gameobject spawn (GUID: {}) defined for pool id ({}), skipped.", guid, pool_id);
575 TC_LOG_ERROR(
"sql.sql",
"`pool_gameobject` pool id ({}) is not in `pool_template`, skipped.", pool_id);
579 if (chance < 0 || chance > 100)
581 TC_LOG_ERROR(
"sql.sql",
"`pool_gameobject` has an invalid chance ({}) for gameobject guid ({}) in pool id ({}), skipped.", chance, guid, pool_id);
586 if (pPoolTemplate->
MapId == -1)
591 TC_LOG_ERROR(
"sql.sql",
"`pool_gameobject` has gameobject spawns on multiple different maps for gameobject guid ({}) in pool id ({}), skipped.", guid, pool_id);
604 while (result->NextRow());
612 TC_LOG_INFO(
"server.loading",
"Loading Mother Pooling Data...");
621 TC_LOG_INFO(
"server.loading",
">> Loaded 0 pools in pools");
628 Field* fields = result->Fetch();
632 float chance = fields[2].
GetFloat();
638 TC_LOG_ERROR(
"sql.sql",
"`pool_pool` mother_pool id ({}) is not in `pool_template`, skipped.", mother_pool_id);
646 TC_LOG_ERROR(
"sql.sql",
"`pool_pool` included pool_id ({}) is not in `pool_template`, skipped.", child_pool_id);
650 if (mother_pool_id == child_pool_id)
652 TC_LOG_ERROR(
"sql.sql",
"`pool_pool` pool_id ({}) includes itself, dead-lock detected, skipped.", child_pool_id);
655 if (chance < 0 || chance > 100)
657 TC_LOG_ERROR(
"sql.sql",
"`pool_pool` has an invalid chance ({}) for pool id ({}) in mother pool id ({}), skipped.", chance, child_pool_id, mother_pool_id);
670 while (result->NextRow());
676 std::set<uint32> checkedPools;
686 TC_LOG_ERROR(
"sql.sql",
"`pool_pool` has child pools on multiple maps in pool id ({}), skipped.", poolItr->second);
694 checkedPools.insert(poolItr->first);
695 if (checkedPools.find(poolItr->second) != checkedPools.end())
697 TC_LOG_ERROR(
"sql.sql",
"The pool(s) {} create(s) a circular reference, which can cause the server to freeze.\nRemoving the last link between mother pool {} and child pool {}",
698 fmt::join(checkedPools,
" "), poolItr->first, poolItr->second);
715 TC_LOG_ERROR(
"sql.sql",
"Pool Id {} is empty (has no creatures and no gameobects and either no child pools or child pools are all empty. The pool will not be spawned", poolId);
718 ASSERT(templateData.MapId != -1);
722 TC_LOG_INFO(
"server.loading",
"Starting objects pooling system...");
726 QueryResult result =
WorldDatabase.Query(
"SELECT DISTINCT pool_template.entry, pool_members.spawnId, pool_members.poolSpawnId FROM pool_template"
727 " LEFT JOIN game_event_pool ON pool_template.entry = game_event_pool.pool_entry"
728 " LEFT JOIN pool_members ON pool_members.type = 2 AND pool_template.entry = pool_members.spawnId WHERE game_event_pool.pool_entry IS NULL");
732 TC_LOG_INFO(
"server.loading",
">> Pool handling system initialized, 0 pools spawned.");
739 Field* fields = result->Fetch();
751 TC_LOG_ERROR(
"sql.sql",
"Pool Id {} has no equal chance pooled entites defined and explicit chance sum is not 100. This broken pool is a child pool of Id {} and cannot be safely removed.", pool_entry, fields[2].GetUInt32());
753 TC_LOG_ERROR(
"sql.sql",
"Pool Id {} has no equal chance pooled entites defined and explicit chance sum is not 100. The pool will not be spawned.", pool_entry);
764 while (result->NextRow());
779 it->second.SpawnObject(spawnedPoolData,
mPoolTemplate[pool_id].MaxLimit, db_guid);
789 it->second.SpawnObject(spawnedPoolData,
mPoolTemplate[pool_id].MaxLimit, db_guid);
799 it->second.SpawnObject(spawnedPoolData,
mPoolTemplate[pool_id].MaxLimit, sub_pool_id);
804 SpawnPool<Pool>(spawnedPoolData, pool_id, 0);
805 SpawnPool<GameObject>(spawnedPoolData, pool_id, 0);
806 SpawnPool<Creature>(spawnedPoolData, pool_id, 0);
815 it->second.DespawnObject(spawnedPoolData, 0, alwaysDeleteRespawnTime);
820 it->second.DespawnObject(spawnedPoolData, 0, alwaysDeleteRespawnTime);
825 it->second.DespawnObject(spawnedPoolData, 0, alwaysDeleteRespawnTime);
835 return IsPartOfAPool<Creature>(spawnId);
837 return IsPartOfAPool<GameObject>(spawnId);
841 ABORT_MSG(
"Invalid spawn type %u passed to PoolMgr::IsPartOfPool (with spawnId " UI64FMTD ")",
uint32(type), spawnId);
893 if (
uint32 motherpoolid = IsPartOfAPool<Pool>(pool_id))
894 SpawnPool<Pool>(spawnedPoolData, motherpoolid, pool_id);
896 SpawnPool<T>(spawnedPoolData, pool_id, db_guid_or_pool_id);
908 UpdatePool<Creature>(spawnedPoolData, pool_id, spawnId);
911 UpdatePool<GameObject>(spawnedPoolData, pool_id, spawnId);
914 ABORT_MSG(
"Invalid spawn type %u passed to PoolMgr::IsPartOfPool (with spawnId " UI64FMTD ")",
uint32(type), spawnId);
920 std::unique_ptr<SpawnedPoolData> spawnedPoolData = std::make_unique<SpawnedPoolData>(map);
922 for (
uint32 poolId : *poolIds)
925 return spawnedPoolData;
std::shared_ptr< ResultSet > QueryResult
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
#define TC_LOG_DEBUG(filterType__, message__,...)
#define TC_LOG_ERROR(filterType__, message__,...)
#define TC_LOG_INFO(filterType__, message__,...)
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
static Creature * CreateCreatureFromDB(ObjectGuid::LowType spawnId, Map *map, bool addToMap=true, bool allowDuplicate=false)
bool GetRespawnCompatibilityMode() const
void SaveRespawnTime(uint32 forceDelay=0)
Class used to access individual fields of database query result.
float GetFloat() const noexcept
uint64 GetUInt64() const noexcept
uint32 GetUInt32() const noexcept
bool isSpawnedByDefault() const
static GameObject * CreateGameObjectFromDB(ObjectGuid::LowType spawnId, Map *map, bool addToMap=true)
void SaveRespawnTime(uint32 forceDelay=0)
bool GetRespawnCompatibilityMode()
void RemoveRespawnTime(SpawnObjectType type, ObjectGuid::LowType spawnId, CharacterDatabaseTransaction dbTrans=nullptr, bool alwaysDeleteFromDB=false)
GameObjectBySpawnIdContainer & GetGameObjectBySpawnIdStore()
bool IsGridLoaded(uint32 gridId) const
CreatureBySpawnIdContainer & GetCreatureBySpawnIdStore()
void SetPoolId(uint32 pool_id)
void ReSpawn1Object(SpawnedPoolData &spawns, PoolObject *obj)
void DespawnObject(SpawnedPoolData &spawns, uint64 guid=0, bool alwaysDeleteRespawnTime=false)
void Despawn1Object(SpawnedPoolData &spawns, uint64 guid, bool alwaysDeleteRespawnTime=false, bool saveRespawnTime=true)
void RemoveOneRelation(uint32 child_pool_id)
void Spawn1Object(SpawnedPoolData &spawns, PoolObject *obj)
void AddEntry(PoolObject &poolitem, uint32 maxentries)
bool isEmptyDeepCheck() const
void RemoveRespawnTimeFromDB(SpawnedPoolData &spawns, uint64 guid)
std::vector< PoolObject > PoolObjectList
void SpawnObject(SpawnedPoolData &spawns, uint32 limit, uint64 triggerFrom)
std::pair< uint64, uint32 > SearchPair
bool IsEmpty(uint32 pool_id) const
bool CheckPool(uint32 pool_id) const
std::unique_ptr< SpawnedPoolData > InitPoolsForMap(Map *map)
void UpdatePool(SpawnedPoolData &spawnedPoolData, uint32 pool_id, uint64 db_guid_or_pool_id)
static PoolMgr * instance()
void SpawnPool(SpawnedPoolData &spawnedPoolData, uint32 pool_id)
PoolTemplateData const * GetPoolTemplate(uint16 pool_id) const
PoolGroupCreatureMap mPoolCreatureGroups
PoolGroupPoolMap mPoolPoolGroups
SearchMap mGameobjectSearchMap
PoolTemplateDataMap mPoolTemplate
std::unordered_map< uint32, std::vector< uint32 > > mAutoSpawnPoolsPerMap
uint32 IsPartOfAPool(uint64 db_guid_or_pool_id) const
PoolGroupGameObjectMap mPoolGameobjectGroups
void DespawnPool(SpawnedPoolData &spawnedPoolData, uint32 pool_id, bool alwaysDeleteRespawnTime=false)
SearchMap mCreatureSearchMap
SpawnedPoolObjects mSpawnedCreatures
SpawnedPoolObjects mSpawnedGameobjects
SpawnedPoolData(Map *owner)
void AddSpawn(uint64 db_guid_or_pool_id, uint32 pool_id)
uint32 GetSpawnedObjects(uint32 pool_id) const
bool IsSpawnedObject(uint64 db_guid_or_pool_id) const
void RemoveSpawn(uint64 db_guid_or_pool_id, uint32 pool_id)
SpawnedPoolPools mSpawnedPools
void AddObjectToRemoveList()
auto MapGetValuePtr(M &map, typename M::key_type const &key)
void RandomResize(C &container, std::size_t requestedSize)
PoolObject(uint64 _guid, float _chance)