public void LoadFromDB() { // Pool templates { uint oldMSTime = Time.GetMSTime(); SQLResult result = DB.World.Query("SELECT entry, max_limit FROM pool_template"); if (result.IsEmpty()) { mPoolTemplate.Clear(); Log.outInfo(LogFilter.ServerLoading, "Loaded 0 object pools. DB table `pool_template` is empty."); return; } uint count = 0; do { uint pool_id = result.Read <uint>(0); PoolTemplateData pPoolTemplate = new PoolTemplateData(); pPoolTemplate.MaxLimit = result.Read <uint>(1); mPoolTemplate[pool_id] = pPoolTemplate; ++count; }while (result.NextRow()); Log.outInfo(LogFilter.ServerLoading, "Loaded {0} objects pools in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime)); } // Creatures Log.outInfo(LogFilter.ServerLoading, "Loading Creatures Pooling Data..."); { uint oldMSTime = Time.GetMSTime(); // 1 2 3 SQLResult result = DB.World.Query("SELECT guid, pool_entry, chance FROM pool_creature"); if (result.IsEmpty()) { Log.outInfo(LogFilter.ServerLoading, "Loaded 0 creatures in pools. DB table `pool_creature` is empty."); } else { uint count = 0; do { ulong guid = result.Read <ulong>(0); uint pool_id = result.Read <uint>(1); float chance = result.Read <float>(2); CreatureData data = Global.ObjectMgr.GetCreatureData(guid); if (data == null) { Log.outError(LogFilter.Sql, "`pool_creature` has a non existing creature spawn (GUID: {0}) defined for pool id ({1}), skipped.", guid, pool_id); continue; } if (!mPoolTemplate.ContainsKey(pool_id)) { Log.outError(LogFilter.Sql, "`pool_creature` pool id ({0}) is not in `pool_template`, skipped.", pool_id); continue; } if (chance < 0 || chance > 100) { Log.outError(LogFilter.Sql, "`pool_creature` has an invalid chance ({0}) for creature guid ({1}) in pool id ({2}), skipped.", chance, guid, pool_id); continue; } PoolTemplateData pPoolTemplate = mPoolTemplate[pool_id]; PoolObject plObject = new PoolObject(guid, chance); if (!mPoolCreatureGroups.ContainsKey(pool_id)) { mPoolCreatureGroups[pool_id] = new PoolGroup <Creature>(); } PoolGroup <Creature> cregroup = mPoolCreatureGroups[pool_id]; cregroup.SetPoolId(pool_id); cregroup.AddEntry(plObject, pPoolTemplate.MaxLimit); mCreatureSearchMap.Add(guid, pool_id); ++count; }while (result.NextRow()); Log.outInfo(LogFilter.ServerLoading, "Loaded {0} creatures in pools in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime)); } } // Gameobjects Log.outInfo(LogFilter.ServerLoading, "Loading Gameobject Pooling Data..."); { uint oldMSTime = Time.GetMSTime(); // 1 2 3 SQLResult result = DB.World.Query("SELECT guid, pool_entry, chance FROM pool_gameobject"); if (result.IsEmpty()) { Log.outInfo(LogFilter.ServerLoading, "Loaded 0 gameobjects in pools. DB table `pool_gameobject` is empty."); } else { uint count = 0; do { ulong guid = result.Read <ulong>(0); uint pool_id = result.Read <uint>(1); float chance = result.Read <float>(2); GameObjectData data = Global.ObjectMgr.GetGOData(guid); if (data == null) { Log.outError(LogFilter.Sql, "`pool_gameobject` has a non existing gameobject spawn (GUID: {0}) defined for pool id ({1}), skipped.", guid, pool_id); continue; } GameObjectTemplate goinfo = Global.ObjectMgr.GetGameObjectTemplate(data.id); if (goinfo.type != GameObjectTypes.Chest && goinfo.type != GameObjectTypes.FishingHole && goinfo.type != GameObjectTypes.GatheringNode && goinfo.type != GameObjectTypes.Goober) { Log.outError(LogFilter.Sql, "`pool_gameobject` has a not lootable gameobject spawn (GUID: {0}, type: {1}) defined for pool id ({2}), skipped.", guid, goinfo.type, pool_id); continue; } if (!mPoolTemplate.ContainsKey(pool_id)) { Log.outError(LogFilter.Sql, "`pool_gameobject` pool id ({0}) is not in `pool_template`, skipped.", pool_id); continue; } if (chance < 0 || chance > 100) { Log.outError(LogFilter.Sql, "`pool_gameobject` has an invalid chance ({0}) for gameobject guid ({1}) in pool id ({2}), skipped.", chance, guid, pool_id); continue; } PoolTemplateData pPoolTemplate = mPoolTemplate[pool_id]; PoolObject plObject = new PoolObject(guid, chance); if (!mPoolGameobjectGroups.ContainsKey(pool_id)) { mPoolGameobjectGroups[pool_id] = new PoolGroup <GameObject>(); } PoolGroup <GameObject> gogroup = mPoolGameobjectGroups[pool_id]; gogroup.SetPoolId(pool_id); gogroup.AddEntry(plObject, pPoolTemplate.MaxLimit); mGameobjectSearchMap.Add(guid, pool_id); ++count; }while (result.NextRow()); Log.outInfo(LogFilter.ServerLoading, "Loaded {0} gameobject in pools in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime)); } } // Pool of pools Log.outInfo(LogFilter.ServerLoading, "Loading Mother Pooling Data..."); { uint oldMSTime = Time.GetMSTime(); // 1 2 3 SQLResult result = DB.World.Query("SELECT pool_id, mother_pool, chance FROM pool_pool"); if (result.IsEmpty()) { Log.outInfo(LogFilter.ServerLoading, "Loaded 0 pools in pools"); } else { uint count = 0; do { uint child_pool_id = result.Read <uint>(0); uint mother_pool_id = result.Read <uint>(1); float chance = result.Read <float>(2); if (!mPoolTemplate.ContainsKey(mother_pool_id)) { Log.outError(LogFilter.Sql, "`pool_pool` mother_pool id ({0}) is not in `pool_template`, skipped.", mother_pool_id); continue; } if (!mPoolTemplate.ContainsKey(child_pool_id)) { Log.outError(LogFilter.Sql, "`pool_pool` included pool_id ({0}) is not in `pool_template`, skipped.", child_pool_id); continue; } if (mother_pool_id == child_pool_id) { Log.outError(LogFilter.Sql, "`pool_pool` pool_id ({0}) includes itself, dead-lock detected, skipped.", child_pool_id); continue; } if (chance < 0 || chance > 100) { Log.outError(LogFilter.Sql, "`pool_pool` has an invalid chance ({0}) for pool id ({1}) in mother pool id ({2}), skipped.", chance, child_pool_id, mother_pool_id); continue; } PoolTemplateData pPoolTemplateMother = mPoolTemplate[mother_pool_id]; PoolObject plObject = new PoolObject(child_pool_id, chance); if (!mPoolPoolGroups.ContainsKey(mother_pool_id)) { mPoolPoolGroups[mother_pool_id] = new PoolGroup <Pool>(); } PoolGroup <Pool> plgroup = mPoolPoolGroups[mother_pool_id]; plgroup.SetPoolId(mother_pool_id); plgroup.AddEntry(plObject, pPoolTemplateMother.MaxLimit); mPoolSearchMap.Add(child_pool_id, mother_pool_id); ++count; }while (result.NextRow()); Log.outInfo(LogFilter.ServerLoading, "Loaded {0} pools in mother pools in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime)); } } Log.outInfo(LogFilter.ServerLoading, "Loading Quest Pooling Data..."); { uint oldMSTime = Time.GetMSTime(); PreparedStatement stmt = DB.World.GetPreparedStatement(WorldStatements.SEL_QUEST_POOLS); SQLResult result = DB.World.Query(stmt); if (result.IsEmpty()) { Log.outInfo(LogFilter.ServerLoading, "Loaded 0 quests in pools"); } else { List <uint> creBounds; List <uint> goBounds; Dictionary <uint, eQuestTypes> poolTypeMap = new Dictionary <uint, eQuestTypes>(); uint count = 0; do { uint entry = result.Read <uint>(0); uint pool_id = result.Read <uint>(1); if (!poolTypeMap.ContainsKey(pool_id)) { poolTypeMap[pool_id] = 0; } Quest quest = Global.ObjectMgr.GetQuestTemplate(entry); if (quest == null) { Log.outError(LogFilter.Sql, "`pool_quest` has a non existing quest template (Entry: {0}) defined for pool id ({1}), skipped.", entry, pool_id); continue; } if (!mPoolTemplate.ContainsKey(pool_id)) { Log.outError(LogFilter.Sql, "`pool_quest` pool id ({0}) is not in `pool_template`, skipped.", pool_id); continue; } if (!quest.IsDailyOrWeekly()) { Log.outError(LogFilter.Sql, "`pool_quest` has an quest ({0}) which is not daily or weekly in pool id ({1}), use ExclusiveGroup instead, skipped.", entry, pool_id); continue; } if (poolTypeMap[pool_id] == eQuestTypes.None) { poolTypeMap[pool_id] = quest.IsDaily() ? eQuestTypes.Daily : eQuestTypes.Weekly; } eQuestTypes currType = quest.IsDaily() ? eQuestTypes.Daily : eQuestTypes.Weekly; if (poolTypeMap[pool_id] != currType) { Log.outError(LogFilter.Sql, "`pool_quest` quest {0} is {1} but pool ({2}) is specified for {3}, mixing not allowed, skipped.", entry, currType, pool_id, poolTypeMap[pool_id]); continue; } creBounds = mQuestCreatureRelation.LookupByKey(entry); goBounds = mQuestGORelation.LookupByKey(entry); if (creBounds.Empty() && goBounds.Empty()) { Log.outError(LogFilter.Sql, "`pool_quest` lists entry ({0}) as member of pool ({1}) but is not started anywhere, skipped.", entry, pool_id); continue; } PoolTemplateData pPoolTemplate = mPoolTemplate[pool_id]; PoolObject plObject = new PoolObject(entry, 0.0f); if (!mPoolQuestGroups.ContainsKey(pool_id)) { mPoolQuestGroups[pool_id] = new PoolGroup <Quest>(); } PoolGroup <Quest> questgroup = mPoolQuestGroups[pool_id]; questgroup.SetPoolId(pool_id); questgroup.AddEntry(plObject, pPoolTemplate.MaxLimit); mQuestSearchMap.Add(entry, pool_id); ++count; }while (result.NextRow()); Log.outInfo(LogFilter.ServerLoading, "Loaded {0} quests in pools in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime)); } } // The initialize method will spawn all pools not in an event and not in another pool, this is why there is 2 left joins with 2 null checks Log.outInfo(LogFilter.ServerLoading, "Starting objects pooling system..."); { uint oldMSTime = Time.GetMSTime(); SQLResult result = DB.World.Query("SELECT DISTINCT pool_template.entry, pool_pool.pool_id, pool_pool.mother_pool FROM pool_template" + " LEFT JOIN game_event_pool ON pool_template.entry=game_event_pool.pool_entry" + " LEFT JOIN pool_pool ON pool_template.entry=pool_pool.pool_id WHERE game_event_pool.pool_entry IS NULL"); if (result.IsEmpty()) { Log.outInfo(LogFilter.ServerLoading, "Pool handling system initialized, 0 pools spawned."); } else { uint count = 0; do { uint pool_entry = result.Read <uint>(0); uint pool_pool_id = result.Read <uint>(1); if (!CheckPool(pool_entry)) { if (pool_pool_id != 0) { // The pool is a child pool in pool_pool table. Ideally we should remove it from the pool handler to ensure it never gets spawned, // however that could recursively invalidate entire chain of mother pools. It can be done in the future but for now we'll do nothing. Log.outError(LogFilter.Sql, "Pool Id {0} has no equal chance pooled entites defined and explicit chance sum is not 100. This broken pool is a child pool of Id {1} and cannot be safely removed.", pool_entry, result.Read <uint>(2)); } else { Log.outError(LogFilter.Sql, "Pool Id {0} has no equal chance pooled entites defined and explicit chance sum is not 100. The pool will not be spawned.", pool_entry); } continue; } // Don't spawn child pools, they are spawned recursively by their parent pools if (pool_pool_id == 0) { SpawnPool(pool_entry); count++; } }while (result.NextRow()); Log.outDebug(LogFilter.Pool, "Pool handling system initialized, {0} pools spawned in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime)); } } }
public void LoadFromDB() { // Pool templates { uint oldMSTime = Time.GetMSTime(); SQLResult result = DB.World.Query("SELECT entry, max_limit FROM pool_template"); if (result.IsEmpty()) { mPoolTemplate.Clear(); Log.outInfo(LogFilter.ServerLoading, "Loaded 0 object pools. DB table `pool_template` is empty."); return; } uint count = 0; do { uint pool_id = result.Read <uint>(0); PoolTemplateData pPoolTemplate = new(); pPoolTemplate.MaxLimit = result.Read <uint>(1); mPoolTemplate[pool_id] = pPoolTemplate; ++count; }while (result.NextRow()); Log.outInfo(LogFilter.ServerLoading, "Loaded {0} objects pools in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime)); } // Creatures Log.outInfo(LogFilter.ServerLoading, "Loading Creatures Pooling Data..."); { uint oldMSTime = Time.GetMSTime(); // 1 2 3 SQLResult result = DB.World.Query("SELECT spawnId, poolSpawnId, chance FROM pool_members WHERE type = 0"); if (result.IsEmpty()) { Log.outInfo(LogFilter.ServerLoading, "Loaded 0 creatures in pools. DB table `pool_creature` is empty."); } else { uint count = 0; do { ulong guid = result.Read <ulong>(0); uint pool_id = result.Read <uint>(1); float chance = result.Read <float>(2); CreatureData data = Global.ObjectMgr.GetCreatureData(guid); if (data == null) { Log.outError(LogFilter.Sql, "`pool_creature` has a non existing creature spawn (GUID: {0}) defined for pool id ({1}), skipped.", guid, pool_id); continue; } if (!mPoolTemplate.ContainsKey(pool_id)) { Log.outError(LogFilter.Sql, "`pool_creature` pool id ({0}) is not in `pool_template`, skipped.", pool_id); continue; } if (chance < 0 || chance > 100) { Log.outError(LogFilter.Sql, "`pool_creature` has an invalid chance ({0}) for creature guid ({1}) in pool id ({2}), skipped.", chance, guid, pool_id); continue; } PoolTemplateData pPoolTemplate = mPoolTemplate[pool_id]; PoolObject plObject = new(guid, chance); if (!mPoolCreatureGroups.ContainsKey(pool_id)) { mPoolCreatureGroups[pool_id] = new PoolGroup <Creature>(); } PoolGroup <Creature> cregroup = mPoolCreatureGroups[pool_id]; cregroup.SetPoolId(pool_id); cregroup.AddEntry(plObject, pPoolTemplate.MaxLimit); mCreatureSearchMap.Add(guid, pool_id); ++count; }while (result.NextRow()); Log.outInfo(LogFilter.ServerLoading, "Loaded {0} creatures in pools in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime)); } } // Gameobjects Log.outInfo(LogFilter.ServerLoading, "Loading Gameobject Pooling Data..."); { uint oldMSTime = Time.GetMSTime(); // 1 2 3 SQLResult result = DB.World.Query("SELECT spawnId, poolSpawnId, chance FROM pool_members WHERE type = 1"); if (result.IsEmpty()) { Log.outInfo(LogFilter.ServerLoading, "Loaded 0 gameobjects in pools. DB table `pool_gameobject` is empty."); } else { uint count = 0; do { ulong guid = result.Read <ulong>(0); uint pool_id = result.Read <uint>(1); float chance = result.Read <float>(2); GameObjectData data = Global.ObjectMgr.GetGameObjectData(guid); if (data == null) { Log.outError(LogFilter.Sql, "`pool_gameobject` has a non existing gameobject spawn (GUID: {0}) defined for pool id ({1}), skipped.", guid, pool_id); continue; } GameObjectTemplate goinfo = Global.ObjectMgr.GetGameObjectTemplate(data.Id); if (goinfo.type != GameObjectTypes.Chest && goinfo.type != GameObjectTypes.FishingHole && goinfo.type != GameObjectTypes.GatheringNode && goinfo.type != GameObjectTypes.Goober) { Log.outError(LogFilter.Sql, "`pool_gameobject` has a not lootable gameobject spawn (GUID: {0}, type: {1}) defined for pool id ({2}), skipped.", guid, goinfo.type, pool_id); continue; } if (!mPoolTemplate.ContainsKey(pool_id)) { Log.outError(LogFilter.Sql, "`pool_gameobject` pool id ({0}) is not in `pool_template`, skipped.", pool_id); continue; } if (chance < 0 || chance > 100) { Log.outError(LogFilter.Sql, "`pool_gameobject` has an invalid chance ({0}) for gameobject guid ({1}) in pool id ({2}), skipped.", chance, guid, pool_id); continue; } PoolTemplateData pPoolTemplate = mPoolTemplate[pool_id]; PoolObject plObject = new(guid, chance); if (!mPoolGameobjectGroups.ContainsKey(pool_id)) { mPoolGameobjectGroups[pool_id] = new PoolGroup <GameObject>(); } PoolGroup <GameObject> gogroup = mPoolGameobjectGroups[pool_id]; gogroup.SetPoolId(pool_id); gogroup.AddEntry(plObject, pPoolTemplate.MaxLimit); mGameobjectSearchMap.Add(guid, pool_id); ++count; }while (result.NextRow()); Log.outInfo(LogFilter.ServerLoading, "Loaded {0} gameobject in pools in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime)); } } // Pool of pools Log.outInfo(LogFilter.ServerLoading, "Loading Mother Pooling Data..."); { uint oldMSTime = Time.GetMSTime(); // 1 2 3 SQLResult result = DB.World.Query("SELECT spawnId, poolSpawnId, chance FROM pool_members WHERE type = 2"); if (result.IsEmpty()) { Log.outInfo(LogFilter.ServerLoading, "Loaded 0 pools in pools"); } else { uint count = 0; do { uint child_pool_id = result.Read <uint>(0); uint mother_pool_id = result.Read <uint>(1); float chance = result.Read <float>(2); if (!mPoolTemplate.ContainsKey(mother_pool_id)) { Log.outError(LogFilter.Sql, "`pool_pool` mother_pool id ({0}) is not in `pool_template`, skipped.", mother_pool_id); continue; } if (!mPoolTemplate.ContainsKey(child_pool_id)) { Log.outError(LogFilter.Sql, "`pool_pool` included pool_id ({0}) is not in `pool_template`, skipped.", child_pool_id); continue; } if (mother_pool_id == child_pool_id) { Log.outError(LogFilter.Sql, "`pool_pool` pool_id ({0}) includes itself, dead-lock detected, skipped.", child_pool_id); continue; } if (chance < 0 || chance > 100) { Log.outError(LogFilter.Sql, "`pool_pool` has an invalid chance ({0}) for pool id ({1}) in mother pool id ({2}), skipped.", chance, child_pool_id, mother_pool_id); continue; } PoolTemplateData pPoolTemplateMother = mPoolTemplate[mother_pool_id]; PoolObject plObject = new(child_pool_id, chance); if (!mPoolPoolGroups.ContainsKey(mother_pool_id)) { mPoolPoolGroups[mother_pool_id] = new PoolGroup <Pool>(); } PoolGroup <Pool> plgroup = mPoolPoolGroups[mother_pool_id]; plgroup.SetPoolId(mother_pool_id); plgroup.AddEntry(plObject, pPoolTemplateMother.MaxLimit); mPoolSearchMap.Add(child_pool_id, mother_pool_id); ++count; }while (result.NextRow()); Log.outInfo(LogFilter.ServerLoading, "Loaded {0} pools in mother pools in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime)); } } // The initialize method will spawn all pools not in an event and not in another pool, this is why there is 2 left joins with 2 null checks Log.outInfo(LogFilter.ServerLoading, "Starting objects pooling system..."); { uint oldMSTime = Time.GetMSTime(); SQLResult result = DB.World.Query("SELECT DISTINCT pool_template.entry, pool_members.spawnId, pool_members.poolSpawnId FROM pool_template" + " LEFT JOIN game_event_pool ON pool_template.entry=game_event_pool.pool_entry" + " LEFT JOIN pool_members ON pool_members.type = 2 AND pool_template.entry = pool_members.spawnId WHERE game_event_pool.pool_entry IS NULL"); if (result.IsEmpty()) { Log.outInfo(LogFilter.ServerLoading, "Pool handling system initialized, 0 pools spawned."); } else { uint count = 0; do { uint pool_entry = result.Read <uint>(0); uint pool_pool_id = result.Read <uint>(1); if (!CheckPool(pool_entry)) { if (pool_pool_id != 0) { // The pool is a child pool in pool_pool table. Ideally we should remove it from the pool handler to ensure it never gets spawned, // however that could recursively invalidate entire chain of mother pools. It can be done in the future but for now we'll do nothing. Log.outError(LogFilter.Sql, "Pool Id {0} has no equal chance pooled entites defined and explicit chance sum is not 100. This broken pool is a child pool of Id {1} and cannot be safely removed.", pool_entry, result.Read <uint>(2)); } else { Log.outError(LogFilter.Sql, "Pool Id {0} has no equal chance pooled entites defined and explicit chance sum is not 100. The pool will not be spawned.", pool_entry); } continue; } // Don't spawn child pools, they are spawned recursively by their parent pools if (pool_pool_id == 0) { SpawnPool(pool_entry); count++; } }while (result.NextRow()); Log.outInfo(LogFilter.ServerLoading, "Pool handling system initialized, {0} pools spawned in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime)); } } }