Exemple #1
0
        public long GetSubsequentResetTime(uint mapid, Difficulty difficulty, long resetTime)
        {
            MapDifficultyRecord mapDiff = Global.DB2Mgr.GetMapDifficultyData(mapid, difficulty);

            if (mapDiff == null || mapDiff.GetRaidDuration() == 0)
            {
                Log.outError(LogFilter.Misc, "InstanceSaveManager.GetSubsequentResetTime: not valid difficulty or no reset delay for map {0}", mapid);
                return(0);
            }

            long diff   = WorldConfig.GetIntValue(WorldCfg.InstanceResetTimeHour) * Time.Hour;
            long period = (uint)(((mapDiff.GetRaidDuration() * WorldConfig.GetFloatValue(WorldCfg.RateInstanceResetTime)) / Time.Day) * Time.Day);

            if (period < Time.Day)
            {
                period = Time.Day;
            }

            return(((resetTime + Time.Minute) / Time.Day * Time.Day) + period + diff);
        }
        void HandleMoveWorldportAck()
        {
            // ignore unexpected far teleports
            if (!GetPlayer().IsBeingTeleportedFar())
            {
                return;
            }

            bool seamlessTeleport = GetPlayer().IsBeingTeleportedSeamlessly();

            GetPlayer().SetSemaphoreTeleportFar(false);

            // get the teleport destination
            WorldLocation loc = GetPlayer().GetTeleportDest();

            // possible errors in the coordinate validity check
            if (!GridDefines.IsValidMapCoord(loc))
            {
                LogoutPlayer(false);
                return;
            }

            // get the destination map entry, not the current one, this will fix homebind and reset greeting
            MapRecord        mapEntry  = CliDB.MapStorage.LookupByKey(loc.GetMapId());
            InstanceTemplate mInstance = Global.ObjectMgr.GetInstanceTemplate(loc.GetMapId());

            // reset instance validity, except if going to an instance inside an instance
            if (!GetPlayer().m_InstanceValid&& mInstance == null)
            {
                GetPlayer().m_InstanceValid = true;
            }

            Map oldMap = GetPlayer().GetMap();
            Map newMap = Global.MapMgr.CreateMap(loc.GetMapId(), GetPlayer());

            if (GetPlayer().IsInWorld)
            {
                Log.outError(LogFilter.Network, "Player (Name {0}) is still in world when teleported from map {1} to new map {2}", GetPlayer().GetName(), oldMap.GetId(), loc.GetMapId());
                oldMap.RemovePlayerFromMap(GetPlayer(), false);
            }

            // relocate the player to the teleport destination
            // the CannotEnter checks are done in TeleporTo but conditions may change
            // while the player is in transit, for example the map may get full
            if (newMap == null || newMap.CannotEnter(GetPlayer()) != 0)
            {
                Log.outError(LogFilter.Network, "Map {0} could not be created for {1} ({2}), porting player to homebind", loc.GetMapId(), newMap ? newMap.GetMapName() : "Unknown", GetPlayer().GetGUID().ToString());
                GetPlayer().TeleportTo(GetPlayer().GetHomebind());
                return;
            }

            float z = loc.GetPositionZ();

            if (GetPlayer().HasUnitMovementFlag(MovementFlag.Hover))
            {
                z += GetPlayer().m_unitData.HoverHeight;
            }

            GetPlayer().Relocate(loc.GetPositionX(), loc.GetPositionY(), z, loc.GetOrientation());
            GetPlayer().SetFallInformation(0, GetPlayer().GetPositionZ());

            GetPlayer().ResetMap();
            GetPlayer().SetMap(newMap);

            ResumeToken resumeToken = new ResumeToken();

            resumeToken.SequenceIndex = _player.m_movementCounter;
            resumeToken.Reason        = seamlessTeleport ? 2 : 1u;
            SendPacket(resumeToken);

            if (!seamlessTeleport)
            {
                GetPlayer().SendInitialPacketsBeforeAddToMap();
            }

            if (!GetPlayer().GetMap().AddPlayerToMap(GetPlayer(), !seamlessTeleport))
            {
                Log.outError(LogFilter.Network, "WORLD: failed to teleport player {0} ({1}) to map {2} ({3}) because of unknown reason!",
                             GetPlayer().GetName(), GetPlayer().GetGUID().ToString(), loc.GetMapId(), newMap ? newMap.GetMapName() : "Unknown");
                GetPlayer().ResetMap();
                GetPlayer().SetMap(oldMap);
                GetPlayer().TeleportTo(GetPlayer().GetHomebind());
                return;
            }

            // Battleground state prepare (in case join to BG), at relogin/tele player not invited
            // only add to bg group and object, if the player was invited (else he entered through command)
            if (GetPlayer().InBattleground())
            {
                // cleanup setting if outdated
                if (!mapEntry.IsBattlegroundOrArena())
                {
                    // We're not in BG
                    GetPlayer().SetBattlegroundId(0, BattlegroundTypeId.None);
                    // reset destination bg team
                    GetPlayer().SetBGTeam(0);
                }
                // join to bg case
                else
                {
                    Battleground bg = GetPlayer().GetBattleground();
                    if (bg)
                    {
                        if (GetPlayer().IsInvitedForBattlegroundInstance(GetPlayer().GetBattlegroundId()))
                        {
                            bg.AddPlayer(GetPlayer());
                        }
                    }
                }
            }

            if (!seamlessTeleport)
            {
                GetPlayer().SendInitialPacketsAfterAddToMap();
            }
            else
            {
                GetPlayer().UpdateVisibilityForPlayer();
                Garrison garrison = GetPlayer().GetGarrison();
                if (garrison != null)
                {
                    garrison.SendRemoteInfo();
                }
            }

            // flight fast teleport case
            if (GetPlayer().GetMotionMaster().GetCurrentMovementGeneratorType() == MovementGeneratorType.Flight)
            {
                if (!GetPlayer().InBattleground())
                {
                    if (!seamlessTeleport)
                    {
                        // short preparations to continue flight
                        IMovementGenerator movementGenerator = GetPlayer().GetMotionMaster().Top();
                        movementGenerator.Initialize(GetPlayer());
                    }
                    return;
                }

                // Battlegroundstate prepare, stop flight
                GetPlayer().GetMotionMaster().MovementExpired();
                GetPlayer().CleanupAfterTaxiFlight();
            }

            // resurrect character at enter into instance where his corpse exist after add to map
            if (mapEntry.IsDungeon() && !GetPlayer().IsAlive())
            {
                if (GetPlayer().GetCorpseLocation().GetMapId() == mapEntry.Id)
                {
                    GetPlayer().ResurrectPlayer(0.5f, false);
                    GetPlayer().SpawnCorpseBones();
                }
            }

            bool allowMount = !mapEntry.IsDungeon() || mapEntry.IsBattlegroundOrArena();

            if (mInstance != null)
            {
                // check if this instance has a reset time and send it to player if so
                Difficulty          diff    = newMap.GetDifficultyID();
                MapDifficultyRecord mapDiff = Global.DB2Mgr.GetMapDifficultyData(mapEntry.Id, diff);
                if (mapDiff != null)
                {
                    if (mapDiff.GetRaidDuration() != 0)
                    {
                        long timeReset = Global.InstanceSaveMgr.GetResetTimeFor(mapEntry.Id, diff);
                        if (timeReset != 0)
                        {
                            uint timeleft = (uint)(timeReset - Time.UnixTime);
                            GetPlayer().SendInstanceResetWarning(mapEntry.Id, diff, timeleft, true);
                        }
                    }
                }

                // check if instance is valid
                if (!GetPlayer().CheckInstanceValidity(false))
                {
                    GetPlayer().m_InstanceValid = false;
                }

                // instance mounting is handled in InstanceTemplate
                allowMount = mInstance.AllowMount;
            }

            // mount allow check
            if (!allowMount)
            {
                GetPlayer().RemoveAurasByType(AuraType.Mounted);
            }

            // update zone immediately, otherwise leave channel will cause crash in mtmap
            uint newzone, newarea;

            GetPlayer().GetZoneAndAreaId(out newzone, out newarea);
            GetPlayer().UpdateZone(newzone, newarea);

            // honorless target
            if (GetPlayer().pvpInfo.IsHostile)
            {
                GetPlayer().CastSpell(GetPlayer(), 2479, true);
            }

            // in friendly area
            else if (GetPlayer().IsPvP() && !GetPlayer().HasPlayerFlag(PlayerFlags.InPVP))
            {
                GetPlayer().UpdatePvP(false, false);
            }

            // resummon pet
            GetPlayer().ResummonPetTemporaryUnSummonedIfAny();

            //lets process all delayed operations on successful teleport
            GetPlayer().ProcessDelayedOperations();
        }
Exemple #3
0
        void LoadResetTimes()
        {
            long now   = Time.UnixTime;
            long today = (now / Time.Day) * Time.Day;

            // NOTE: Use DirectPExecute for tables that will be queried later

            // get the current reset times for normal instances (these may need to be updated)
            // these are only kept in memory for InstanceSaves that are loaded later
            // resettime = 0 in the DB for raid/heroic instances so those are skipped
            Dictionary <uint, Tuple <uint, long> > instResetTime = new Dictionary <uint, Tuple <uint, long> >();

            // index instance ids by map/difficulty pairs for fast reset warning send
            MultiMap <uint, uint> mapDiffResetInstances = new MultiMap <uint, uint>();

            SQLResult result = DB.Characters.Query("SELECT id, map, difficulty, resettime FROM instance ORDER BY id ASC");

            if (!result.IsEmpty())
            {
                do
                {
                    uint instanceId = result.Read <uint>(0);

                    // Instances are pulled in ascending order from db and nextInstanceId is initialized with 1,
                    // so if the instance id is used, increment until we find the first unused one for a potential new instance
                    if (Global.MapMgr.GetNextInstanceId() == instanceId)
                    {
                        Global.MapMgr.SetNextInstanceId(instanceId + 1);
                    }

                    // Mark instance id as being used
                    Global.MapMgr.RegisterInstanceId(instanceId);
                    long resettime = result.Read <uint>(3);
                    if (resettime != 0)
                    {
                        uint mapid      = result.Read <ushort>(1);
                        uint difficulty = result.Read <byte>(2);

                        instResetTime[instanceId] = Tuple.Create(MathFunctions.MakePair32(mapid, difficulty), resettime);
                        mapDiffResetInstances.Add(MathFunctions.MakePair32(mapid, difficulty), instanceId);
                    }
                }while (result.NextRow());

                // update reset time for normal instances with the max creature respawn time + X hours
                SQLResult result2 = DB.Characters.Query(DB.Characters.GetPreparedStatement(CharStatements.SEL_MAX_CREATURE_RESPAWNS));
                if (!result2.IsEmpty())
                {
                    do
                    {
                        uint instance  = result2.Read <uint>(1);
                        long resettime = result2.Read <uint>(0) + 2 * Time.Hour;
                        var  pair      = instResetTime.LookupByKey(instance);
                        if (pair != null && pair.Item2 != resettime)
                        {
                            DB.Characters.DirectExecute("UPDATE instance SET resettime = '{0}' WHERE id = '{1}'", resettime, instance);
                            instResetTime[instance] = Tuple.Create(pair.Item1, resettime);
                        }
                    }while (result2.NextRow());
                }

                // schedule the reset times
                foreach (var pair in instResetTime)
                {
                    if (pair.Value.Item2 > now)
                    {
                        ScheduleReset(true, pair.Value.Item2, new InstResetEvent(0, MathFunctions.Pair32_LoPart(pair.Value.Item1), (Difficulty)MathFunctions.Pair32_HiPart(pair.Value.Item1), pair.Key));
                    }
                }
            }

            // load the global respawn times for raid/heroic instances
            uint diff = (uint)(WorldConfig.GetIntValue(WorldCfg.InstanceResetTimeHour) * Time.Hour);

            result = DB.Characters.Query("SELECT mapid, difficulty, resettime FROM instance_reset");
            if (!result.IsEmpty())
            {
                do
                {
                    uint       mapid        = result.Read <ushort>(0);
                    Difficulty difficulty   = (Difficulty)result.Read <byte>(1);
                    ulong      oldresettime = result.Read <uint>(2);

                    MapDifficultyRecord mapDiff = Global.DB2Mgr.GetMapDifficultyData(mapid, difficulty);
                    if (mapDiff == null)
                    {
                        Log.outError(LogFilter.Server, "InstanceSaveManager.LoadResetTimes: invalid mapid({0})/difficulty({1}) pair in instance_reset!", mapid, difficulty);
                        DB.Characters.DirectExecute("DELETE FROM instance_reset WHERE mapid = '{0}' AND difficulty = '{1}'", mapid, difficulty);
                        continue;
                    }

                    // update the reset time if the hour in the configs changes
                    ulong newresettime = (oldresettime / Time.Day) * Time.Day + diff;
                    if (oldresettime != newresettime)
                    {
                        DB.Characters.DirectExecute("UPDATE instance_reset SET resettime = '{0}' WHERE mapid = '{1}' AND difficulty = '{2}'", newresettime, mapid, difficulty);
                    }

                    InitializeResetTimeFor(mapid, difficulty, (long)newresettime);
                } while (result.NextRow());
            }

            // calculate new global reset times for expired instances and those that have never been reset yet
            // add the global reset times to the priority queue
            foreach (var mapDifficultyPair in Global.DB2Mgr.GetMapDifficulties())
            {
                uint mapid = mapDifficultyPair.Key;

                foreach (var difficultyPair in mapDifficultyPair.Value)
                {
                    Difficulty          difficulty = (Difficulty)difficultyPair.Key;
                    MapDifficultyRecord mapDiff    = difficultyPair.Value;
                    if (mapDiff.GetRaidDuration() == 0)
                    {
                        continue;
                    }

                    // the reset_delay must be at least one day
                    uint period = (uint)(((mapDiff.GetRaidDuration() * WorldConfig.GetFloatValue(WorldCfg.RateInstanceResetTime)) / Time.Day) * Time.Day);
                    if (period < Time.Day)
                    {
                        period = Time.Day;
                    }

                    long t = GetResetTimeFor(mapid, difficulty);
                    if (t == 0)
                    {
                        // initialize the reset time
                        t = today + period + diff;
                        DB.Characters.DirectExecute("INSERT INTO instance_reset VALUES ('{0}', '{1}', '{2}')", mapid, (uint)difficulty, (uint)t);
                    }

                    if (t < now)
                    {
                        // assume that expired instances have already been cleaned
                        // calculate the next reset time
                        t  = (t / Time.Day) * Time.Day;
                        t += ((today - t) / period + 1) * period + diff;
                        DB.Characters.DirectExecute("UPDATE instance_reset SET resettime = '{0}' WHERE mapid = '{1}' AND difficulty= '{2}'", t, mapid, (uint)difficulty);
                    }

                    InitializeResetTimeFor(mapid, difficulty, t);

                    // schedule the global reset/warning
                    byte type;
                    for (type = 1; type < 4; ++type)
                    {
                        if (t - ResetTimeDelay[type - 1] > now)
                        {
                            break;
                        }
                    }

                    ScheduleReset(true, t - ResetTimeDelay[type - 1], new InstResetEvent(type, mapid, difficulty, 0));

                    var range = mapDiffResetInstances.LookupByKey(MathFunctions.MakePair32(mapid, (uint)difficulty));
                    foreach (var id in range)
                    {
                        ScheduleReset(true, t - ResetTimeDelay[type - 1], new InstResetEvent(type, mapid, difficulty, id));
                    }
                }
            }
        }
        void LoadResetTimes()
        {
            long now   = GameTime.GetGameTime();
            long today = (now / Time.Day) * Time.Day;

            // NOTE: Use DirectPExecute for tables that will be queried later

            // get the current reset times for normal instances (these may need to be updated)
            // these are only kept in memory for InstanceSaves that are loaded later
            // resettime = 0 in the DB for raid/heroic instances so those are skipped
            Dictionary <uint, Tuple <uint, long> > instResetTime = new();

            // index instance ids by map/difficulty pairs for fast reset warning send
            MultiMap <uint, uint> mapDiffResetInstances = new();

            SQLResult result = DB.Characters.Query("SELECT id, map, difficulty, resettime FROM instance ORDER BY id ASC");

            if (!result.IsEmpty())
            {
                do
                {
                    uint instanceId = result.Read <uint>(0);

                    // Mark instance id as being used
                    Global.MapMgr.RegisterInstanceId(instanceId);
                    long resettime = result.Read <long>(3);
                    if (resettime != 0)
                    {
                        uint mapid      = result.Read <ushort>(1);
                        uint difficulty = result.Read <byte>(2);

                        instResetTime[instanceId] = Tuple.Create(MathFunctions.MakePair32(mapid, difficulty), resettime);
                        mapDiffResetInstances.Add(MathFunctions.MakePair32(mapid, difficulty), instanceId);
                    }
                }while (result.NextRow());

                // schedule the reset times
                foreach (var pair in instResetTime)
                {
                    if (pair.Value.Item2 > now)
                    {
                        ScheduleReset(true, pair.Value.Item2, new InstResetEvent(0, MathFunctions.Pair32_LoPart(pair.Value.Item1), (Difficulty)MathFunctions.Pair32_HiPart(pair.Value.Item1), pair.Key));
                    }
                }
            }

            // load the global respawn times for raid/heroic instances
            uint diff = (uint)(WorldConfig.GetIntValue(WorldCfg.InstanceResetTimeHour) * Time.Hour);

            result = DB.Characters.Query("SELECT mapid, difficulty, resettime FROM instance_reset");
            if (!result.IsEmpty())
            {
                do
                {
                    uint       mapid        = result.Read <ushort>(0);
                    Difficulty difficulty   = (Difficulty)result.Read <byte>(1);
                    long       oldresettime = result.Read <long>(2);

                    MapDifficultyRecord mapDiff = Global.DB2Mgr.GetMapDifficultyData(mapid, difficulty);
                    if (mapDiff == null)
                    {
                        Log.outError(LogFilter.Server, "InstanceSaveManager.LoadResetTimes: invalid mapid({0})/difficulty({1}) pair in instance_reset!", mapid, difficulty);
                        PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_GLOBAL_INSTANCE_RESETTIME);
                        stmt.AddValue(0, mapid);
                        stmt.AddValue(1, (byte)difficulty);
                        DB.Characters.DirectExecute(stmt);
                        continue;
                    }

                    // update the reset time if the hour in the configs changes
                    long newresettime = (oldresettime / Time.Day) * Time.Day + diff;
                    if (oldresettime != newresettime)
                    {
                        PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_GLOBAL_INSTANCE_RESETTIME);
                        stmt.AddValue(0, newresettime);
                        stmt.AddValue(1, mapid);
                        stmt.AddValue(2, (byte)difficulty);
                        DB.Characters.DirectExecute(stmt);
                    }

                    InitializeResetTimeFor(mapid, difficulty, newresettime);
                } while (result.NextRow());
            }

            // calculate new global reset times for expired instances and those that have never been reset yet
            // add the global reset times to the priority queue
            foreach (var mapDifficultyPair in Global.DB2Mgr.GetMapDifficulties())
            {
                uint mapid = mapDifficultyPair.Key;

                foreach (var difficultyPair in mapDifficultyPair.Value)
                {
                    Difficulty          difficulty = (Difficulty)difficultyPair.Key;
                    MapDifficultyRecord mapDiff    = difficultyPair.Value;
                    if (mapDiff.GetRaidDuration() == 0)
                    {
                        continue;
                    }

                    // the reset_delay must be at least one day
                    uint period = (uint)(((mapDiff.GetRaidDuration() * WorldConfig.GetFloatValue(WorldCfg.RateInstanceResetTime)) / Time.Day) * Time.Day);
                    if (period < Time.Day)
                    {
                        period = Time.Day;
                    }

                    long t = GetResetTimeFor(mapid, difficulty);
                    if (t == 0)
                    {
                        // initialize the reset time
                        t = today + period + diff;

                        PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_GLOBAL_INSTANCE_RESETTIME);
                        stmt.AddValue(0, mapid);
                        stmt.AddValue(1, (byte)difficulty);
                        stmt.AddValue(2, t);
                        DB.Characters.DirectExecute(stmt);
                    }

                    if (t < now)
                    {
                        // assume that expired instances have already been cleaned
                        // calculate the next reset time
                        t  = (t / Time.Day) * Time.Day;
                        t += ((today - t) / period + 1) * period + diff;

                        PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_GLOBAL_INSTANCE_RESETTIME);
                        stmt.AddValue(0, t);
                        stmt.AddValue(1, mapid);
                        stmt.AddValue(2, (byte)difficulty);
                        DB.Characters.DirectExecute(stmt);
                    }

                    InitializeResetTimeFor(mapid, difficulty, t);

                    // schedule the global reset/warning
                    byte type;
                    for (type = 1; type < 4; ++type)
                    {
                        if (t - ResetTimeDelay[type - 1] > now)
                        {
                            break;
                        }
                    }

                    ScheduleReset(true, t - ResetTimeDelay[type - 1], new InstResetEvent(type, mapid, difficulty, 0));

                    var range = mapDiffResetInstances.LookupByKey(MathFunctions.MakePair32(mapid, (uint)difficulty));
                    foreach (var id in range)
                    {
                        ScheduleReset(true, t - ResetTimeDelay[type - 1], new InstResetEvent(type, mapid, difficulty, id));
                    }
                }
            }
        }