void PoolManager::LoadFromDB() { QueryResult* result = WorldDatabase.Query("SELECT MAX(entry) FROM pool_template"); if (!result) { sLog.outString(">> Table pool_template is empty."); sLog.outString(); return; } else { Field* fields = result->Fetch(); max_pool_id = fields[0].GetUInt16(); delete result; } mPoolTemplate.resize(max_pool_id + 1); result = WorldDatabase.Query("SELECT entry, max_limit, description FROM pool_template"); if (!result) { mPoolTemplate.clear(); sLog.outString(">> Table pool_template is empty:"); sLog.outString(); return; } uint32 count = 0; BarGoLink bar(result->GetRowCount()); do { ++count; Field* fields = result->Fetch(); bar.step(); uint16 pool_id = fields[0].GetUInt16(); PoolTemplateData& pPoolTemplate = mPoolTemplate[pool_id]; pPoolTemplate.MaxLimit = fields[1].GetUInt32(); pPoolTemplate.description = fields[2].GetCppString(); pPoolTemplate.AutoSpawn = true; // will update and later data loading } while (result->NextRow()); sLog.outString(); sLog.outString(">> Loaded %u objects pools", count); delete result; PoolMapChecker mapChecker(mPoolTemplate); // Creatures (guids and entries) mPoolCreatureGroups.resize(max_pool_id + 1); mCreatureSearchMap.clear(); // 1 2 3 result = WorldDatabase.Query("SELECT guid, pool_entry, chance FROM pool_creature"); count = 0; if (!result) { BarGoLink bar2(1); bar2.step(); sLog.outString(); sLog.outString(">> Loaded %u creatures in pools from `pool_creature`", count); } else { BarGoLink bar2(result->GetRowCount()); do { Field* fields = result->Fetch(); bar2.step(); uint32 guid = fields[0].GetUInt32(); uint16 pool_id = fields[1].GetUInt16(); float chance = fields[2].GetFloat(); CreatureData const* data = sObjectMgr.GetCreatureData(guid); if (!data) { sLog.outErrorDb("`pool_creature` has a non existing creature spawn (GUID: %u) defined for pool id (%u), skipped.", guid, pool_id); continue; } if (pool_id > max_pool_id) { sLog.outErrorDb("`pool_creature` pool id (%i) is out of range compared to max pool id in `pool_template`, skipped.", pool_id); continue; } if (chance < 0 || chance > 100) { sLog.outErrorDb("`pool_creature` has an invalid chance (%f) for creature guid (%u) in pool id (%i), skipped.", chance, guid, pool_id); continue; } if (!mapChecker.CheckAndRemember(data->mapid, pool_id, "pool_creature", "creature guid")) continue; PoolTemplateData* pPoolTemplate = &mPoolTemplate[pool_id]; ++count; PoolObject plObject = PoolObject(guid, chance); PoolGroup<Creature>& cregroup = mPoolCreatureGroups[pool_id]; cregroup.SetPoolId(pool_id); cregroup.AddEntry(plObject, pPoolTemplate->MaxLimit); SearchPair p(guid, pool_id); mCreatureSearchMap.insert(p); } while (result->NextRow()); sLog.outString(); sLog.outString(">> Loaded %u creatures in pools from `pool_creature`", count); delete result; } result = WorldDatabase.Query("SELECT guid, pool_entry, chance, pool_creature_template.id FROM pool_creature_template LEFT JOIN creature ON creature.id = pool_creature_template.id"); count = 0; if (!result) { BarGoLink bar2(1); bar2.step(); sLog.outString(); sLog.outString(">> Loaded %u creatures in pools from `pool_creature_template`", count); } else { BarGoLink bar2(result->GetRowCount()); do { Field* fields = result->Fetch(); bar2.step(); uint32 guid = fields[0].GetUInt32(); uint16 pool_id = fields[1].GetUInt16(); float chance = fields[2].GetFloat(); uint16 entry_id = fields[3].GetUInt32(); // for errors output only CreatureData const* data = sObjectMgr.GetCreatureData(guid); if (!data) { sLog.outErrorDb("`pool_creature_template` has a non existing creature spawn (GUID: %u Entry: %u) defined for pool id (%u), skipped.", guid, entry_id, pool_id); continue; } if (pool_id > max_pool_id) { sLog.outErrorDb("`pool_creature_template` pool id (%i) is out of range compared to max pool id in `pool_template`, skipped.", pool_id); continue; } if (chance < 0 || chance > 100) { sLog.outErrorDb("`pool_creature_template` has an invalid chance (%f) for creature (Guid %u Entry %u) in pool id (%i), skipped.", chance, guid, entry_id, pool_id); continue; } // `pool_creature` and `pool_creature_template` can't have guids duplicates (in second case because entries also unique) // So if guid already listed in pools then this duplicate from alt.table // Also note: for added guid not important what case we skip from 2 tables if (uint16 alt_pool_id = IsPartOfAPool<Creature>(guid)) { sLog.outErrorDb("`pool_creature` has guid %u for pool %u that already added to pool %u from `pool_creature_template` for creature entry %u, skipped.", guid, pool_id, alt_pool_id, entry_id); continue; } if (!mapChecker.CheckAndRemember(data->mapid, pool_id, "pool_creature_template", "creature guid")) continue; PoolTemplateData* pPoolTemplate = &mPoolTemplate[pool_id]; ++count; PoolObject plObject = PoolObject(guid, chance); PoolGroup<Creature>& cregroup = mPoolCreatureGroups[pool_id]; cregroup.SetPoolId(pool_id); cregroup.AddEntry(plObject, pPoolTemplate->MaxLimit); SearchPair p(guid, pool_id); mCreatureSearchMap.insert(p); } while (result->NextRow()); sLog.outString(); sLog.outString(">> Loaded %u creatures in pools from `pool_creature_template`", count); delete result; } // Gameobjects (guids and entries) mPoolGameobjectGroups.resize(max_pool_id + 1); mGameobjectSearchMap.clear(); // 1 2 3 result = WorldDatabase.Query("SELECT guid, pool_entry, chance FROM pool_gameobject"); count = 0; if (!result) { BarGoLink bar2(1); bar2.step(); sLog.outString(); sLog.outString(">> Loaded %u gameobject in pools from `pool_gameobject`", count); } else { BarGoLink bar2(result->GetRowCount()); do { Field* fields = result->Fetch(); bar2.step(); uint32 guid = fields[0].GetUInt32(); uint16 pool_id = fields[1].GetUInt16(); float chance = fields[2].GetFloat(); GameObjectData const* data = sObjectMgr.GetGOData(guid); if (!data) { sLog.outErrorDb("`pool_gameobject` has a non existing gameobject spawn (GUID: %u) defined for pool id (%u), skipped.", guid, pool_id); continue; } GameObjectInfo const* goinfo = ObjectMgr::GetGameObjectInfo(data->id); if (goinfo->type != GAMEOBJECT_TYPE_CHEST && goinfo->type != GAMEOBJECT_TYPE_GOOBER && goinfo->type != GAMEOBJECT_TYPE_FISHINGHOLE && goinfo->type != GAMEOBJECT_TYPE_TRAP) { sLog.outErrorDb("`pool_gameobject` has a not lootable gameobject spawn (GUID: %u, type: %u) defined for pool id (%u), skipped.", guid, goinfo->type, pool_id); continue; } if (pool_id > max_pool_id) { sLog.outErrorDb("`pool_gameobject` pool id (%i) is out of range compared to max pool id in `pool_template`, skipped.", pool_id); continue; } if (chance < 0 || chance > 100) { sLog.outErrorDb("`pool_gameobject` has an invalid chance (%f) for gameobject guid (%u) in pool id (%i), skipped.", chance, guid, pool_id); continue; } if (!mapChecker.CheckAndRemember(data->mapid, pool_id, "pool_gameobject", "gameobject guid")) continue; PoolTemplateData* pPoolTemplate = &mPoolTemplate[pool_id]; ++count; PoolObject plObject = PoolObject(guid, chance); PoolGroup<GameObject>& gogroup = mPoolGameobjectGroups[pool_id]; gogroup.SetPoolId(pool_id); gogroup.AddEntry(plObject, pPoolTemplate->MaxLimit); SearchPair p(guid, pool_id); mGameobjectSearchMap.insert(p); } while (result->NextRow()); sLog.outString(); sLog.outString(">> Loaded %u gameobject in pools from `pool_gameobject`", count); delete result; } // 1 2 3 result = WorldDatabase.Query("SELECT guid, pool_entry, chance, pool_gameobject_template.id FROM pool_gameobject_template LEFT JOIN gameobject ON gameobject.id = pool_gameobject_template.id"); count = 0; if (!result) { BarGoLink bar2(1); bar2.step(); sLog.outString(); sLog.outString(">> Loaded %u gameobject in pools from `pool_gameobject_template`", count); } else { BarGoLink bar2(result->GetRowCount()); do { Field* fields = result->Fetch(); bar2.step(); uint32 guid = fields[0].GetUInt32(); uint16 pool_id = fields[1].GetUInt16(); float chance = fields[2].GetFloat(); uint16 entry_id = fields[3].GetUInt32(); // for errors output only GameObjectData const* data = sObjectMgr.GetGOData(guid); if (!data) { sLog.outErrorDb("`pool_gameobject_template` has a non existing gameobject spawn (GUID: %u Entry %u) defined for pool id (%u), skipped.", guid, entry_id, pool_id); continue; } GameObjectInfo const* goinfo = ObjectMgr::GetGameObjectInfo(data->id); if (goinfo->type != GAMEOBJECT_TYPE_CHEST && goinfo->type != GAMEOBJECT_TYPE_GOOBER && goinfo->type != GAMEOBJECT_TYPE_FISHINGHOLE && goinfo->type != GAMEOBJECT_TYPE_TRAP) { sLog.outErrorDb("`pool_gameobject_template` has a not lootable gameobject spawn (GUID: %u Entry %u Type: %u) defined for pool id (%u), skipped.", guid, entry_id, goinfo->type, pool_id); continue; } if (pool_id > max_pool_id) { sLog.outErrorDb("`pool_gameobject_template` pool id (%i) is out of range compared to max pool id in `pool_template`, skipped.", pool_id); continue; } if (chance < 0 || chance > 100) { sLog.outErrorDb("`pool_gameobject_template` has an invalid chance (%f) for gameobject (Guid %u Entry %u) in pool id (%i), skipped.", chance, guid, entry_id, pool_id); continue; } // `pool_gameobject` and `pool_gameobject_template` can't have guids duplicates (in second case because entries also unique) // So if guid already listed in pools then this duplicate from alt.table // Also note: for added guid not important what case we skip from 2 tables if (uint16 alt_pool_id = IsPartOfAPool<GameObject>(guid)) { sLog.outErrorDb("`pool_gameobject` has guid %u for pool %u that already added to pool %u from `pool_gameobject_template` for gameobject entry %u, skipped.", guid, pool_id, alt_pool_id, entry_id); continue; } if (!mapChecker.CheckAndRemember(data->mapid, pool_id, "pool_gameobject_template", "gameobject guid")) continue; PoolTemplateData* pPoolTemplate = &mPoolTemplate[pool_id]; ++count; PoolObject plObject = PoolObject(guid, chance); PoolGroup<GameObject>& gogroup = mPoolGameobjectGroups[pool_id]; gogroup.SetPoolId(pool_id); gogroup.AddEntry(plObject, pPoolTemplate->MaxLimit); SearchPair p(guid, pool_id); mGameobjectSearchMap.insert(p); } while (result->NextRow()); sLog.outString(); sLog.outString(">> Loaded %u gameobject in pools from `pool_gameobject_template`", count); delete result; } // Pool of pools mPoolPoolGroups.resize(max_pool_id + 1); // 1 2 3 result = WorldDatabase.Query("SELECT pool_id, mother_pool, chance FROM pool_pool"); count = 0; if (!result) { BarGoLink bar2(1); bar2.step(); sLog.outString(); sLog.outString(">> Loaded %u pools in pools", count); } else { BarGoLink bar2(result->GetRowCount()); do { Field* fields = result->Fetch(); bar2.step(); uint16 child_pool_id = fields[0].GetUInt16(); uint16 mother_pool_id = fields[1].GetUInt16(); float chance = fields[2].GetFloat(); if (mother_pool_id > max_pool_id) { sLog.outErrorDb("`pool_pool` mother_pool id (%i) is out of range compared to max pool id in `pool_template`, skipped.", mother_pool_id); continue; } if (child_pool_id > max_pool_id) { sLog.outErrorDb("`pool_pool` included pool_id (%i) is out of range compared to max pool id in `pool_template`, skipped.", child_pool_id); continue; } if (mother_pool_id == child_pool_id) { sLog.outErrorDb("`pool_pool` pool_id (%i) includes itself, dead-lock detected, skipped.", child_pool_id); continue; } if (chance < 0 || chance > 100) { sLog.outErrorDb("`pool_pool` has an invalid chance (%f) for pool id (%u) in mother pool id (%i), skipped.", chance, child_pool_id, mother_pool_id); continue; } PoolTemplateData* pPoolTemplateMother = &mPoolTemplate[mother_pool_id]; ++count; PoolObject plObject = PoolObject(child_pool_id, chance); PoolGroup<Pool>& plgroup = mPoolPoolGroups[mother_pool_id]; plgroup.SetPoolId(mother_pool_id); plgroup.AddEntry(plObject, pPoolTemplateMother->MaxLimit); SearchPair p(child_pool_id, mother_pool_id); mPoolSearchMap.insert(p); // update top independent pool flag mPoolTemplate[child_pool_id].AutoSpawn = false; } while (result->NextRow()); // Now check for circular reference for (uint16 i = 0; i < max_pool_id; ++i) { std::set<uint16> checkedPools; for (SearchMap::iterator poolItr = mPoolSearchMap.find(i); poolItr != mPoolSearchMap.end(); poolItr = mPoolSearchMap.find(poolItr->second)) { // if child pool not have map data then it empty or have not checked child then will checked and all line later if (MapEntry const* childMapEntry = mPoolTemplate[poolItr->first].mapEntry) { if (!mapChecker.CheckAndRemember(childMapEntry->MapID, poolItr->second, "pool_pool", "pool with creature/gameobject")) { mPoolPoolGroups[poolItr->second].RemoveOneRelation(poolItr->first); mPoolSearchMap.erase(poolItr); --count; break; } } checkedPools.insert(poolItr->first); if (checkedPools.find(poolItr->second) != checkedPools.end()) { std::ostringstream ss; ss << "The pool(s) "; for (std::set<uint16>::const_iterator itr = checkedPools.begin(); itr != checkedPools.end(); ++itr) ss << *itr << " "; ss << "create(s) a circular reference, which can cause the server to freeze.\nRemoving the last link between mother pool " << poolItr->first << " and child pool " << poolItr->second; sLog.outErrorDb("%s", ss.str().c_str()); mPoolPoolGroups[poolItr->second].RemoveOneRelation(poolItr->first); mPoolSearchMap.erase(poolItr); --count; break; } } } sLog.outString(); sLog.outString(">> Loaded %u pools in mother pools", count); delete result; } // check chances integrity for (uint16 pool_entry = 0; pool_entry < mPoolTemplate.size(); ++pool_entry) { if (mPoolTemplate[pool_entry].AutoSpawn) { if (!CheckPool(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); mPoolTemplate[pool_entry].AutoSpawn = false; } } } }
void PoolManager::LoadFromDB() { QueryResult* result = WorldDatabase.Query("SELECT MAX(entry) FROM pool_template"); if (!result) { sLog.outString(">> Table pool_template is empty."); sLog.outString(); return; } else { Field* fields = result->Fetch(); max_pool_id = fields[0].GetUInt16(); delete result; } mPoolTemplate.resize(max_pool_id + 1); result = WorldDatabase.Query("SELECT entry, max_limit, description FROM pool_template"); if (!result) { mPoolTemplate.clear(); sLog.outString(">> Table pool_template is empty:"); sLog.outString(); return; } uint32 count = 0; BarGoLink bar(result->GetRowCount()); do { ++count; Field* fields = result->Fetch(); bar.step(); uint16 pool_id = fields[0].GetUInt16(); PoolTemplateData& pPoolTemplate = mPoolTemplate[pool_id]; pPoolTemplate.MaxLimit = fields[1].GetUInt32(); pPoolTemplate.description = fields[2].GetCppString(); pPoolTemplate.AutoSpawn = true; // will update and later data loading } while (result->NextRow()); sLog.outString(); sLog.outString(">> Loaded %u objects pools", count); delete result; PoolMapChecker mapChecker(mPoolTemplate); // Creatures (guids and entries) mPoolCreatureGroups.resize(max_pool_id + 1); mCreatureSearchMap.clear(); // 1 2 3 result = WorldDatabase.Query("SELECT guid, pool_entry, chance FROM pool_creature"); count = 0; if (!result) { BarGoLink bar2(1); bar2.step(); sLog.outString(); sLog.outString(">> Loaded %u creatures in pools from `pool_creature`", count); } else { BarGoLink bar2(result->GetRowCount()); do { Field* fields = result->Fetch(); bar2.step(); uint32 guid = fields[0].GetUInt32(); uint16 pool_id = fields[1].GetUInt16(); float chance = fields[2].GetFloat(); CreatureData const* data = sObjectMgr.GetCreatureData(guid); if (!data) { sLog.outErrorDb("`pool_creature` has a non existing creature spawn (GUID: %u) defined for pool id (%u), skipped.", guid, pool_id); continue; } if (pool_id > max_pool_id) { sLog.outErrorDb("`pool_creature` pool id (%i) is out of range compared to max pool id in `pool_template`, skipped.", pool_id); continue; } if (chance < 0 || chance > 100) { sLog.outErrorDb("`pool_creature` has an invalid chance (%f) for creature guid (%u) in pool id (%i), skipped.", chance, guid, pool_id); continue; } if (!mapChecker.CheckAndRemember(data->mapid, pool_id, "pool_creature", "creature guid", guid)) { continue; } PoolTemplateData* pPoolTemplate = &mPoolTemplate[pool_id]; ++count; PoolObject plObject = PoolObject(guid, chance); PoolGroup<Creature>& cregroup = mPoolCreatureGroups[pool_id]; cregroup.SetPoolId(pool_id); cregroup.AddEntry(plObject, pPoolTemplate->MaxLimit); SearchPair p(guid, pool_id); mCreatureSearchMap.insert(p); } while (result->NextRow()); sLog.outString(); sLog.outString(">> Loaded %u creatures in pools from `pool_creature`", count); delete result; } result = WorldDatabase.Query("SELECT guid, pool_entry, chance, pool_creature_template.id FROM pool_creature_template LEFT JOIN creature ON creature.id = pool_creature_template.id"); count = 0; if (!result) { BarGoLink bar2(1); bar2.step(); sLog.outString(); sLog.outString(">> Loaded %u creatures in pools from `pool_creature_template`", count); } else { BarGoLink bar2(result->GetRowCount()); do { Field* fields = result->Fetch(); bar2.step(); uint32 guid = fields[0].GetUInt32(); uint16 pool_id = fields[1].GetUInt16(); float chance = fields[2].GetFloat(); uint16 entry_id = fields[3].GetUInt32(); // for errors output only CreatureData const* data = sObjectMgr.GetCreatureData(guid); if (!data) { sLog.outErrorDb("`pool_creature_template` has a non existing creature spawn (GUID: %u Entry: %u) defined for pool id (%u), skipped.", guid, entry_id, pool_id); continue; } if (pool_id > max_pool_id) { sLog.outErrorDb("`pool_creature_template` pool id (%i) is out of range compared to max pool id in `pool_template`, skipped.", pool_id); continue; } if (chance < 0 || chance > 100) { sLog.outErrorDb("`pool_creature_template` has an invalid chance (%f) for creature (Guid %u Entry %u) in pool id (%i), skipped.", chance, guid, entry_id, pool_id); continue; } // `pool_creature` and `pool_creature_template` can't have guids duplicates (in second case because entries also unique) // So if guid already listed in pools then this duplicate from alt.table // Also note: for added guid not important what case we skip from 2 tables if (uint16 alt_pool_id = IsPartOfAPool<Creature>(guid)) { sLog.outErrorDb("`pool_creature` has guid %u for pool %u that already added to pool %u from `pool_creature_template` for creature entry %u, skipped.", guid, pool_id, alt_pool_id, entry_id); continue; } if (!mapChecker.CheckAndRemember(data->mapid, pool_id, "pool_creature_template", "creature guid", guid)) { continue; } PoolTemplateData* pPoolTemplate = &mPoolTemplate[pool_id]; ++count; PoolObject plObject = PoolObject(guid, chance); PoolGroup<Creature>& cregroup = mPoolCreatureGroups[pool_id]; cregroup.SetPoolId(pool_id); cregroup.AddEntry(plObject, pPoolTemplate->MaxLimit); SearchPair p(guid, pool_id); mCreatureSearchMap.insert(p); } while (result->NextRow()); sLog.outString(); sLog.outString(">> Loaded %u creatures in pools from `pool_creature_template`", count); delete result; } // Gameobjects (guids and entries) mPoolGameobjectGroups.resize(max_pool_id + 1); mGameobjectSearchMap.clear(); // 1 2 3 result = WorldDatabase.Query("SELECT guid, pool_entry, chance FROM pool_gameobject"); count = 0; if (!result) { BarGoLink bar2(1); bar2.step(); sLog.outString(); sLog.outString(">> Loaded %u gameobject in pools from `pool_gameobject`", count); } else { BarGoLink bar2(result->GetRowCount()); do { Field* fields = result->Fetch(); bar2.step(); uint32 guid = fields[0].GetUInt32(); uint16 pool_id = fields[1].GetUInt16(); float chance = fields[2].GetFloat(); GameObjectData const* data = sObjectMgr.GetGOData(guid); if (!data) { sLog.outErrorDb("`pool_gameobject` has a non existing gameobject spawn (GUID: %u) defined for pool id (%u), skipped.", guid, pool_id); continue; } if (pool_id > max_pool_id) { sLog.outErrorDb("`pool_gameobject` pool id (%i) is out of range compared to max pool id in `pool_template`, skipped.", pool_id); continue; } if (chance < 0 || chance > 100) { sLog.outErrorDb("`pool_gameobject` has an invalid chance (%f) for gameobject guid (%u) in pool id (%i), skipped.", chance, guid, pool_id); continue; } if (!mapChecker.CheckAndRemember(data->mapid, pool_id, "pool_gameobject", "gameobject guid", guid)) { continue; } PoolTemplateData* pPoolTemplate = &mPoolTemplate[pool_id]; ++count; PoolObject plObject = PoolObject(guid, chance); PoolGroup<GameObject>& gogroup = mPoolGameobjectGroups[pool_id]; gogroup.SetPoolId(pool_id); gogroup.AddEntry(plObject, pPoolTemplate->MaxLimit); SearchPair p(guid, pool_id); mGameobjectSearchMap.insert(p); } while (result->NextRow()); sLog.outString(); sLog.outString(">> Loaded %u gameobject in pools from `pool_gameobject`", count); delete result; } // 1 2 3 result = WorldDatabase.Query("SELECT guid, pool_entry, chance, pool_gameobject_template.id FROM pool_gameobject_template LEFT JOIN gameobject ON gameobject.id = pool_gameobject_template.id"); count = 0; if (!result) { BarGoLink bar2(1); bar2.step(); sLog.outString(); sLog.outString(">> Loaded %u gameobject in pools from `pool_gameobject_template`", count); } else { BarGoLink bar2(result->GetRowCount()); do { Field* fields = result->Fetch(); bar2.step(); uint32 guid = fields[0].GetUInt32(); uint16 pool_id = fields[1].GetUInt16(); float chance = fields[2].GetFloat(); uint16 entry_id = fields[3].GetUInt32(); // for errors output only GameObjectData const* data = sObjectMgr.GetGOData(guid); if (!data) { sLog.outErrorDb("`pool_gameobject_template` has a non existing gameobject spawn (GUID: %u Entry %u) defined for pool id (%u), skipped.", guid, entry_id, pool_id); continue; } if (pool_id > max_pool_id) { sLog.outErrorDb("`pool_gameobject_template` pool id (%i) is out of range compared to max pool id in `pool_template`, skipped.", pool_id); continue; } if (chance < 0 || chance > 100) { sLog.outErrorDb("`pool_gameobject_template` has an invalid chance (%f) for gameobject (Guid %u Entry %u) in pool id (%i), skipped.", chance, guid, entry_id, pool_id); continue; } // `pool_gameobject` and `pool_gameobject_template` can't have guids duplicates (in second case because entries also unique) // So if guid already listed in pools then this duplicate from alt.table // Also note: for added guid not important what case we skip from 2 tables if (uint16 alt_pool_id = IsPartOfAPool<GameObject>(guid)) { sLog.outErrorDb("`pool_gameobject` has guid %u for pool %u that already added to pool %u from `pool_gameobject_template` for gameobject entry %u, skipped.", guid, pool_id, alt_pool_id, entry_id); continue; } if (!mapChecker.CheckAndRemember(data->mapid, pool_id, "pool_gameobject_template", "gameobject guid", guid)) { continue; } PoolTemplateData* pPoolTemplate = &mPoolTemplate[pool_id]; ++count; PoolObject plObject = PoolObject(guid, chance); PoolGroup<GameObject>& gogroup = mPoolGameobjectGroups[pool_id]; gogroup.SetPoolId(pool_id); gogroup.AddEntry(plObject, pPoolTemplate->MaxLimit); SearchPair p(guid, pool_id); mGameobjectSearchMap.insert(p); } while (result->NextRow()); sLog.outString(); sLog.outString(">> Loaded %u gameobject in pools from `pool_gameobject_template`", count); delete result; } // Pool of pools mPoolPoolGroups.resize(max_pool_id + 1); // 1 2 3 result = WorldDatabase.Query("SELECT pool_id, mother_pool, chance FROM pool_pool"); count = 0; if (!result) { BarGoLink bar2(1); bar2.step(); sLog.outString(); sLog.outString(">> Loaded %u pools in pools", count); } else { BarGoLink bar2(result->GetRowCount()); do { Field* fields = result->Fetch(); bar2.step(); uint16 child_pool_id = fields[0].GetUInt16(); uint16 mother_pool_id = fields[1].GetUInt16(); float chance = fields[2].GetFloat(); if (mother_pool_id > max_pool_id) { sLog.outErrorDb("`pool_pool` mother_pool id (%i) is out of range compared to max pool id in `pool_template`, skipped.", mother_pool_id); continue; } if (child_pool_id > max_pool_id) { sLog.outErrorDb("`pool_pool` included pool_id (%i) is out of range compared to max pool id in `pool_template`, skipped.", child_pool_id); continue; } if (mother_pool_id == child_pool_id) { sLog.outErrorDb("`pool_pool` pool_id (%i) includes itself, dead-lock detected, skipped.", child_pool_id); continue; } if (chance < 0 || chance > 100) { sLog.outErrorDb("`pool_pool` has an invalid chance (%f) for pool id (%u) in mother pool id (%i), skipped.", chance, child_pool_id, mother_pool_id); continue; } PoolTemplateData* pPoolTemplateMother = &mPoolTemplate[mother_pool_id]; ++count; PoolObject plObject = PoolObject(child_pool_id, chance); PoolGroup<Pool>& plgroup = mPoolPoolGroups[mother_pool_id]; plgroup.SetPoolId(mother_pool_id); plgroup.AddEntry(plObject, pPoolTemplateMother->MaxLimit); SearchPair p(child_pool_id, mother_pool_id); mPoolSearchMap.insert(p); // update top independent pool flag mPoolTemplate[child_pool_id].AutoSpawn = false; } while (result->NextRow()); // Now check for circular reference for (uint16 i = 0; i < max_pool_id; ++i) { std::set<uint16> checkedPools; for (SearchMap::iterator poolItr = mPoolSearchMap.find(i); poolItr != mPoolSearchMap.end(); poolItr = mPoolSearchMap.find(poolItr->second)) { // if child pool not have map data then it empty or have not checked child then will checked and all line later if (MapEntry const* childMapEntry = mPoolTemplate[poolItr->first].mapEntry) { if (!mapChecker.CheckAndRemember(childMapEntry->MapID, poolItr->second, "pool_pool", "pool with creature/gameobject", poolItr->first)) { mPoolPoolGroups[poolItr->second].RemoveOneRelation(poolItr->first); mPoolSearchMap.erase(poolItr); --count; break; } } checkedPools.insert(poolItr->first); if (checkedPools.find(poolItr->second) != checkedPools.end()) { std::ostringstream ss; ss << "The pool(s) "; for (std::set<uint16>::const_iterator itr = checkedPools.begin(); itr != checkedPools.end(); ++itr) { ss << *itr << " "; } ss << "create(s) a circular reference, which can cause the server to freeze.\nRemoving the last link between mother pool " << poolItr->first << " and child pool " << poolItr->second; sLog.outErrorDb("%s", ss.str().c_str()); mPoolPoolGroups[poolItr->second].RemoveOneRelation(poolItr->first); mPoolSearchMap.erase(poolItr); --count; break; } } } sLog.outString(); sLog.outString(">> Loaded %u pools in mother pools", count); delete result; } // check chances integrity for (uint16 pool_entry = 0; pool_entry < mPoolTemplate.size(); ++pool_entry) { if (mPoolTemplate[pool_entry].AutoSpawn) { if (!CheckPool(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 can not pick one to spawn.", pool_entry); mPoolTemplate[pool_entry].AutoSpawn = false; } } } /*if (sWorld.getConfig(CONFIG_BOOL_AUTOPOOLING_MINING_ENABLE)) { // autocreate mining pools mPoolTemplate.resize(max_pool_id + 3486 + 533); //values are hardcoded for max zoneID and max MapID it would be better to read max IDs from the .dbc files mPoolCreatureGroups.resize(max_pool_id + 3486 + 533); mPoolGameobjectGroups.resize(max_pool_id + 3486 + 533); mPoolPoolGroups.resize(max_pool_id + 3486 + 533); uint32 max_autopool_entry = (max_pool_id + 3486 + 533); for (uint16 pool_entry = max_pool_id + 1; pool_entry < max_autopool_entry; ++pool_entry) { PoolTemplateData& pPoolTemplate = mPoolTemplate[pool_entry]; pPoolTemplate.MaxLimit = 0; std::ostringstream sZone; sZone << "autopool zone " << pool_entry; pPoolTemplate.description = sZone.str(); pPoolTemplate.AutoSpawn = true; // will update and later data loading } count = 0; // 0 1 2 3 4 5 result = WorldDatabase.Query("SELECT gameobject.guid, gameobject.id, map, position_x, position_y, position_z," // 6 7 "pool_gameobject.pool_entry, pool_gameobject_template.pool_entry " "FROM gameobject " "LEFT OUTER JOIN pool_gameobject ON gameobject.guid = pool_gameobject.guid " "LEFT OUTER JOIN pool_gameobject_template ON gameobject.id = pool_gameobject_template.id"); if (!result) { BarGoLink bar3(1); bar3.step(); sLog.outString(); sLog.outErrorDb(">> Loaded 0 gameobjects. DB table `gameobject` is empty."); return; } BarGoLink bar3(result->GetRowCount()); do { Field* fields = result->Fetch(); bar3.step(); uint32 guid = fields[ 0].GetUInt32(); uint32 entry = fields[ 1].GetUInt32(); uint32 map = fields[ 2].GetUInt32(); float posX = fields[ 3].GetFloat(); float posY = fields[ 4].GetFloat(); float posZ = fields[ 5].GetFloat(); int16 GuidPoolId = fields[6].GetInt16(); int16 EntryPoolId = fields[7].GetInt16(); if (GuidPoolId != 0 || EntryPoolId != 0) // if not this is in the pool system already { continue; } GameObjectInfo const* goinfo = ObjectMgr::GetGameObjectInfo(entry); if (goinfo->type != GAMEOBJECT_TYPE_CHEST) { continue; } if (goinfo->chest.minSuccessOpens != 0 && goinfo->chest.maxSuccessOpens > goinfo->chest.minSuccessOpens) //in this case it is a mineral vein { uint32 zone_id; uint16 pool_id; if (map == 0 || map == 1) { zone_id = sTerrainMgr.LoadTerrain(map)->GetZoneId(posX, posY, posZ); pool_id = zone_id + max_pool_id; } else { zone_id = map; pool_id = zone_id + max_pool_id + 3486; //3486 zero value for maxzoneID } PoolTemplateData* pPoolTemplate = &mPoolTemplate[pool_id]; PoolObject plObject = PoolObject(guid, 0); PoolGroup<GameObject>& gogroup = mPoolGameobjectGroups[pool_id]; gogroup.SetPoolId(pool_id); gogroup.AddEntry(plObject, 0); SearchPair p(guid, pool_id); mGameobjectSearchMap.insert(p); if (!mapChecker.CheckAndRemember(map, pool_id, "pool_gameobject", "gameobject guid", guid)) { continue; } ++count; //sLog.outErrorDb("UPDATE gameobject SET zone_id=%u, area_id=%u WHERE guid=%u;", zoneId, areaId, guid); } } while (result->NextRow()); for (uint16 pool_entry = max_pool_id + 1; pool_entry < max_autopool_entry; ++pool_entry) { uint32 poolsize; PoolTemplateData& pPoolTemplate = mPoolTemplate[pool_entry]; PoolGroup<GameObject>& gogroup = mPoolGameobjectGroups[pool_entry]; poolsize = gogroup.size(); pPoolTemplate.MaxLimit = (poolsize * CONFIG_UINT32_RATE_MINING_AUTOPOOLING) / 100; } delete result; sLog.outString(">> Loaded %u mining nodes", count); }*/ }