Пример #1
0
        void Spawn1Object(PoolObject obj)
        {
            switch (typeof(T).Name)
            {
            case "Creature":
                CreatureData data = Global.ObjectMgr.GetCreatureData(obj.guid);
                if (data != null)
                {
                    Global.ObjectMgr.AddCreatureToGrid(obj.guid, data);

                    // Spawn if necessary (loaded grids only)
                    Map map = Global.MapMgr.CreateBaseMap(data.mapid);
                    // We use spawn coords to spawn
                    if (!map.Instanceable() && map.IsGridLoaded(data.posX, data.posY))
                    {
                        Creature creature = new Creature();
                        if (!creature.LoadCreatureFromDB(obj.guid, map))
                        {
                            return;
                        }
                    }
                }
                break;

            case "GameObject":
                GameObjectData data_ = Global.ObjectMgr.GetGOData(obj.guid);
                if (data_ != null)
                {
                    Global.ObjectMgr.AddGameObjectToGrid(obj.guid, data_);
                    // Spawn if necessary (loaded grids only)
                    // this base map checked as non-instanced and then only existed
                    Map map = Global.MapMgr.CreateBaseMap(data_.mapid);
                    // We use current coords to unspawn, not spawn coords since creature can have changed grid
                    if (!map.Instanceable() && map.IsGridLoaded(data_.posX, data_.posY))
                    {
                        GameObject pGameobject = new GameObject();
                        if (!pGameobject.LoadGameObjectFromDB(obj.guid, map, false))
                        {
                            return;
                        }
                        else
                        {
                            if (pGameobject.isSpawnedByDefault())
                            {
                                map.AddToMap(pGameobject);
                            }
                        }
                    }
                }
                break;

            case "Pool":
                Global.PoolMgr.SpawnPool((uint)obj.guid);
                break;

            case "Quest":
                // Creatures
                var questMap = Global.ObjectMgr.GetCreatureQuestRelationMap();
                var qr       = Global.PoolMgr.mQuestCreatureRelation.LookupByKey(obj.guid);
                foreach (var creature in qr)
                {
                    Log.outDebug(LogFilter.Pool, "PoolGroup<Quest>: Adding quest {0} to creature {1}", obj.guid, creature);
                    questMap.Add(creature, (uint)obj.guid);
                }

                // Gameobjects
                questMap = Global.ObjectMgr.GetGOQuestRelationMap();
                qr       = Global.PoolMgr.mQuestGORelation.LookupByKey(obj.guid);
                foreach (var go in qr)
                {
                    Log.outDebug(LogFilter.Pool, "PoolGroup<Quest>: Adding quest {0} to GO {1}", obj.guid, go);
                    questMap.Add(go, (uint)obj.guid);
                }
                break;
            }
        }
Пример #2
0
        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 out of range compared to max pool id 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 out of range compared to max pool id 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 out of range compared to max pool id 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 out of range compared to max pool id 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 out of range compared to max pool id 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));
                }
            }
        }
Пример #3
0
        void SpawnQuestObject(ActivePoolData spawns, uint limit, ulong triggerFrom)
        {
            Log.outDebug(LogFilter.Pool, "PoolGroup<Quest>: Spawning pool {0}", poolId);
            // load state from db
            if (triggerFrom == 0)
            {
                PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_POOL_QUEST_SAVE);
                stmt.AddValue(0, poolId);
                SQLResult result = DB.Characters.Query(stmt);

                if (!result.IsEmpty())
                {
                    do
                    {
                        uint questId = result.Read <uint>(0);
                        spawns.ActivateObject <Quest>(questId, poolId);
                        PoolObject tempObj = new PoolObject(questId, 0.0f);
                        Spawn1Object(tempObj);
                        --limit;
                    } while (result.NextRow() && limit != 0);
                    return;
                }
            }

            List <ulong> currentQuests = spawns.GetActiveQuests();
            List <ulong> newQuests     = new List <ulong>();

            // always try to select different quests
            foreach (var poolObject in EqualChanced)
            {
                if (spawns.IsActiveObject <Quest>(poolObject.guid))
                {
                    continue;
                }
                newQuests.Add(poolObject.guid);
            }

            // clear the pool
            DespawnObject(spawns);

            // recycle minimal amount of quests if possible count is lower than limit
            if (limit > newQuests.Count && !currentQuests.Empty())
            {
                do
                {
                    ulong questId = currentQuests.SelectRandom();
                    newQuests.Add(questId);
                    currentQuests.Remove(questId);
                } while (newQuests.Count < limit && !currentQuests.Empty()); // failsafe
            }

            if (newQuests.Empty())
            {
                return;
            }

            // activate <limit> random quests
            do
            {
                ulong questId = newQuests.SelectRandom();
                spawns.ActivateObject <Quest>(questId, poolId);
                PoolObject tempObj = new PoolObject(questId, 0.0f);
                Spawn1Object(tempObj);
                newQuests.Remove(questId);
                --limit;
            } while (limit != 0 && !newQuests.Empty());

            // if we are here it means the pool is initialized at startup and did not have previous saved state
            if (triggerFrom == 0)
            {
                Global.PoolMgr.SaveQuestsToDB();
            }
        }
Пример #4
0
 void ReSpawn1Object(PoolObject obj)
 {
     // GameObject/Creature is still on map, nothing to do
 }