示例#1
0
        private static DateTime NotifyPlayersOfPendingShutdown(DateTime lastNoticeTime, DateTime shutdownTime)
        {
            var notify = false;

            var sdt      = shutdownTime - DateTime.UtcNow;
            var timeHrs  = $"{(sdt.Hours >= 1 ? $"{sdt.ToString("%h")}" : "")}{(sdt.Hours >= 2 ? $" hours" : sdt.Hours == 1 ? " hour" : "")}";
            var timeMins = $"{(sdt.Minutes != 0 ? $"{sdt.ToString("%m")}" : "")}{(sdt.Minutes >= 2 ? $" minutes" : sdt.Minutes == 1 ? " minute" : "")}";
            var timeSecs = $"{(sdt.Seconds != 0 ? $"{sdt.ToString("%s")}" : "")}{(sdt.Seconds >= 2 ? $" seconds" : sdt.Seconds == 1 ? " second" : "")}";
            var time     = $"{(timeHrs != "" ? timeHrs : "")}{(timeMins != "" ? $"{((timeHrs != "") ? ", " : "")}" + timeMins : "")}{(timeSecs != "" ? $"{((timeHrs != "" || timeMins != "") ? " and " : "")}" + timeSecs : "")}";

            switch (time)
            {
            case "2 hours":
            case "1 hour":
            case "45 minutes":
            case "30 minutes":
            case "15 minutes":
            case "10 minutes":
            case "5 minutes":
            case "2 minutes":
            case "1 minute and 30 seconds":
            case "1 minute":
            case "30 seconds":
            case "15 seconds":
            case "10 seconds":
            case "5 seconds":
                notify = true;
                break;
            }

            // Console.WriteLine(time);

            if (notify && (DateTime.UtcNow - lastNoticeTime).TotalSeconds > 2)
            {
                foreach (var player in PlayerManager.GetAllOnline())
                {
                    if (sdt.TotalSeconds > 10)
                    {
                        player.Session.WorldBroadcast($"Broadcast from System> {(sdt.TotalMinutes > 1.5 ? "ATTENTION" : "WARNING")} - This Asheron's Call Server is shutting down in {time}.{(sdt.TotalMinutes <= 3 ?  " Please log out." : "")}");
                    }
                    else
                    {
                        player.Session.WorldBroadcast($"Broadcast from System> ATTENTION - This Asheron's Call Server is shutting down NOW!!!!");
                    }
                }

                return(DateTime.UtcNow);
            }
            else
            {
                return(lastNoticeTime);
            }
        }
示例#2
0
        /// <summary>
        /// Threaded task created when performing a server shutdown
        /// </summary>
        private static void ShutdownServer()
        {
            var shutdownTime = DateTime.UtcNow.AddSeconds(ShutdownInterval);

            ShutdownTime = shutdownTime;

            var lastNoticeTime = DateTime.UtcNow;

            // wait for shutdown interval to expire
            while (shutdownTime != DateTime.MinValue && shutdownTime >= DateTime.UtcNow)
            {
                // this allows the server shutdown to be canceled
                if (!ShutdownInitiated)
                {
                    // reset shutdown details
                    string shutdownText = $"The server has canceled the shutdown procedure @ {DateTime.UtcNow} UTC";
                    log.Info(shutdownText);

                    // special text
                    foreach (var player in PlayerManager.GetAllOnline())
                    {
                        player.Session.WorldBroadcast(shutdownText);
                    }

                    // break function
                    return;
                }

                lastNoticeTime = NotifyPlayersOfPendingShutdown(lastNoticeTime, shutdownTime.AddSeconds(1));

                Thread.Sleep(10);
            }

            PropertyManager.ResyncVariables();
            PropertyManager.StopUpdating();

            log.Debug("Logging off all players...");

            // logout each player
            foreach (var player in PlayerManager.GetAllOnline())
            {
                player.Session.LogOffPlayer();
            }

            log.Info("Waiting for all players to log off...");

            // wait 10 seconds for log-off
            while (PlayerManager.GetAllOnline().Count > 0)
            {
                Thread.Sleep(10);
            }

            log.Debug("Adding all landblocks to destruction queue...");

            // Queue unloading of all the landblocks
            // The actual unloading will happen in WorldManager.UpdateGameWorld
            LandblockManager.AddAllActiveLandblocksToDestructionQueue();

            log.Info("Waiting for all active landblocks to unload...");

            while (LandblockManager.GetLoadedLandblocks().Count > 0)
            {
                Thread.Sleep(10);
            }

            log.Debug("Stopping world...");

            // Disabled thread update loop
            WorldManager.StopWorld();

            log.Info("Waiting for world to stop...");

            // Wait for world to end
            while (WorldManager.WorldActive)
            {
                Thread.Sleep(10);
            }

            //log.Info("Saving OfflinePlayers that have unsaved changes...");
            //PlayerManager.SaveOfflinePlayersWithChanges();

            log.Info("Waiting for database queue to empty...");

            // Wait for the database queue to empty
            while (DatabaseManager.Shard.QueueCount > 0)
            {
                Thread.Sleep(10);
            }

            // Write exit to console/log
            log.Info($"Exiting at {DateTime.UtcNow}");

            // System exit
            Environment.Exit(Environment.ExitCode);
        }
示例#3
0
        public void Execute(Emote emote, WorldObject target)
        {
            var player   = target as Player;
            var creature = target as Creature;

            switch (emote.Type)
            {
            case EmoteType.Act:

                if (player != null)
                {
                    WorldObject.ActOnUse(player);
                }
                break;

            case EmoteType.Activate:

                target.Activate(WorldObject);
                break;

            case EmoteType.AddCharacterTitle:

                if (player != null)
                {
                    player.AddTitle((CharacterTitle)emote.Stat);
                }
                break;

            case EmoteType.AddContract:

                if (player != null)
                {
                    player.AddContract(emote.Stat);
                }
                break;

            case EmoteType.AdminSpam:

                var text    = Replace(emote.Message, WorldObject, target);
                var players = PlayerManager.GetAllOnline();
                foreach (var _player in players)
                {
                    _player.Session.Network.EnqueueSend(new GameMessageSystemChat(text, ChatMessageType.AdminTell));
                }
                break;

            case EmoteType.AwardLevelProportionalSkillXP:

                if (player != null)
                {
                    player.GrantLevelProportionalSkillXP((Skill)emote.Stat, emote.Percent, emote.Max);
                }
                break;

            case EmoteType.AwardLevelProportionalXP:

                if (player != null)
                {
                    player.GrantLevelProportionalXp(emote.Percent, emote.Max);
                }
                break;

            case EmoteType.AwardLuminance:

                if (player != null)
                {
                    player.GrantLuminance((long)emote.Amount);
                }
                break;

            case EmoteType.AwardNoShareXP:

                if (player != null)
                {
                    player.EarnXP((long)emote.Amount, false);
                }
                break;

            case EmoteType.AwardSkillPoints:

                if (player != null)
                {
                    player.AwardSkillPoints((Skill)emote.Stat, (uint)emote.Amount);
                }
                break;

            case EmoteType.AwardSkillXP:

                if (player != null)
                {
                    player.RaiseSkillGameAction((Skill)emote.Stat, (uint)emote.Amount, true);
                }
                break;

            case EmoteType.AwardTrainingCredits:

                if (player != null)
                {
                    player.AddSkillCredits((int)emote.Amount, true);
                }
                break;

            case EmoteType.AwardXP:

                if (player != null)
                {
                    player.EarnXP((long)emote.Amount);
                }
                break;

            case EmoteType.BLog:
                break;

            case EmoteType.CastSpell:

                if (WorldObject is Player)
                {
                    (WorldObject as Player).CreatePlayerSpell(emote.SpellId);
                }

                else if (WorldObject is Creature)
                {
                    (WorldObject as Creature).CreateCreatureSpell(target.Guid, emote.SpellId);
                }

                break;

            case EmoteType.CastSpellInstant:

                if (WorldObject is Player)
                {
                    (WorldObject as Player).CreatePlayerSpell(emote.SpellId);
                }

                else if (WorldObject is Creature)
                {
                    (WorldObject as Creature).CreateCreatureSpell(target.Guid, emote.SpellId);
                }

                break;

            case EmoteType.CloseMe:

                target.Close(WorldObject);
                break;

            case EmoteType.CreateTreasure:
                break;

            case EmoteType.DecrementIntStat:

                var id   = (PropertyInt)emote.Stat;
                var prop = target.GetProperty(id);
                if (prop != null)
                {
                    target.SetProperty(id, prop.Value - 1);
                }
                break;

            case EmoteType.DecrementMyQuest:
                break;

            case EmoteType.DecrementQuest:
                break;

            case EmoteType.DeleteSelf:

                WorldObject.CurrentLandblock?.RemoveWorldObject(WorldObject.Guid, false);
                break;

            case EmoteType.DirectBroadcast:

                text = Replace(emote.Message, WorldObject, target);
                if (player != null)
                {
                    player.Session.Network.EnqueueSend(new GameMessageSystemChat(text, ChatMessageType.Broadcast));
                }
                break;

            case EmoteType.EraseMyQuest:
                break;

            case EmoteType.EraseQuest:
                break;

            case EmoteType.FellowBroadcast:

                text = Replace(emote.Message, WorldObject, target);
                if (player != null)
                {
                    var fellowship = player.Fellowship;
                    if (fellowship != null)
                    {
                        player.Session.Network.EnqueueSend(new GameMessageSystemChat(text, ChatMessageType.Broadcast));
                    }
                    else
                    {
                        foreach (var fellow in fellowship.FellowshipMembers)
                        {
                            player.Session.Network.EnqueueSend(new GameMessageSystemChat(text, ChatMessageType.Broadcast));
                        }
                    }
                }
                break;

            case EmoteType.ForceMotion:

                WorldObject.PhysicsObj.DoMotion(emote.Motion, new MovementParameters());
                break;

            case EmoteType.Generate:

                var wcid = emote.CreateProfile.ClassID;
                var item = WorldObjectFactory.CreateNewWorldObject(wcid);
                break;

            case EmoteType.Give:

                if (player != null)
                {
                    wcid = emote.CreateProfile.ClassID;
                    item = WorldObjectFactory.CreateNewWorldObject(wcid);
                    if (item == null)
                    {
                        break;
                    }

                    var success = player.TryAddToInventory(item);
                }
                break;

            case EmoteType.Goto:
                //InqCategory(EmoteCategory.GotoSet, emote);
                break;

            case EmoteType.IncrementIntStat:

                id   = (PropertyInt)emote.Stat;
                prop = target.GetProperty(id);
                if (prop != null)
                {
                    target.SetProperty(id, prop.Value + 1);
                }
                break;

            case EmoteType.IncrementMyQuest:
                break;

            case EmoteType.IncrementQuest:
                break;

            case EmoteType.InflictVitaePenalty:

                if (player != null)
                {
                    player.VitaeCpPool++;
                }
                break;

            case EmoteType.InqAttributeStat:

                if (creature != null)
                {
                    var attr    = creature.Attributes[(PropertyAttribute)emote.Stat];
                    var success = attr != null && attr.Ranks >= emote.Min && attr.Ranks <= emote.Max;
                    InqCategory(success ? EmoteCategory.TestSuccess : EmoteCategory.TestFailure, emote);
                }
                break;

            case EmoteType.InqBoolStat:
                InqProperty(target.GetProperty((PropertyBool)emote.Stat), emote);
                break;

            case EmoteType.InqContractsFull:

                if (player != null)
                {
                    var contracts = player.TrackedContracts;
                    InqCategory(contracts.Count != 0 ? EmoteCategory.TestSuccess : EmoteCategory.TestFailure, emote);
                }
                break;

            case EmoteType.InqEvent:

                var started = EventManager.IsEventStarted(emote.Message);
                InqCategory(started ? EmoteCategory.TestSuccess : EmoteCategory.TestFailure, emote);
                break;

            case EmoteType.InqFellowNum:
                InqCategory(player != null && player.Fellowship != null ? EmoteCategory.TestSuccess : EmoteCategory.TestNoFellow, emote);
                break;

            case EmoteType.InqFellowQuest:
                break;

            case EmoteType.InqFloatStat:
                InqProperty(target.GetProperty((PropertyFloat)emote.Stat), emote);
                break;

            case EmoteType.InqInt64Stat:
                InqProperty(target.GetProperty((PropertyInt64)emote.Stat), emote);
                break;

            case EmoteType.InqIntStat:
                InqProperty(target.GetProperty((PropertyInt)emote.Stat), emote);
                break;

            case EmoteType.InqMyQuest:
                break;

            case EmoteType.InqMyQuestBitsOff:
                break;

            case EmoteType.InqMyQuestBitsOn:
                break;

            case EmoteType.InqMyQuestSolves:
                break;

            case EmoteType.InqNumCharacterTitles:

                if (player != null)
                {
                    InqCategory(player.NumCharacterTitles != 0 ? EmoteCategory.TestSuccess : EmoteCategory.TestFailure, emote);
                }
                break;

            case EmoteType.InqOwnsItems:

                if (player != null)
                {
                    InqCategory(player.Inventory.Count > 0 ? EmoteCategory.TestSuccess : EmoteCategory.TestFailure, emote);
                }
                break;

            case EmoteType.InqPackSpace:

                if (player != null)
                {
                    var freeSpace = player.ContainerCapacity > player.ItemCapacity;
                    InqCategory(freeSpace ? EmoteCategory.TestSuccess : EmoteCategory.TestFailure, emote);
                }
                break;

            case EmoteType.InqQuest:
                break;

            case EmoteType.InqQuestBitsOff:
                break;

            case EmoteType.InqQuestBitsOn:
                break;

            case EmoteType.InqQuestSolves:
                break;

            case EmoteType.InqRawAttributeStat:

                if (creature != null)
                {
                    var attr    = creature.Attributes[(PropertyAttribute)emote.Stat];
                    var success = attr != null && attr.Base >= emote.Min && attr.Base <= emote.Max;
                    InqCategory(success ? EmoteCategory.TestSuccess : EmoteCategory.TestFailure, emote);
                }
                break;

            case EmoteType.InqRawSecondaryAttributeStat:

                if (creature != null)
                {
                    var vital   = creature.Vitals[(PropertyAttribute2nd)emote.Stat];
                    var success = vital != null && vital.Base >= emote.Min && vital.Base <= emote.Max;
                    InqCategory(success ? EmoteCategory.TestSuccess : EmoteCategory.TestFailure, emote);
                }
                break;

            case EmoteType.InqRawSkillStat:

                if (creature != null)
                {
                    var skill   = creature.GetCreatureSkill((Skill)emote.Stat);
                    var success = skill != null && skill.Base >= emote.Min && skill.Base <= emote.Max;
                    InqCategory(success ? EmoteCategory.TestSuccess : EmoteCategory.TestFailure, emote);
                }
                break;

            case EmoteType.InqSecondaryAttributeStat:

                if (creature != null)
                {
                    var vital   = creature.Vitals[(PropertyAttribute2nd)emote.Stat];
                    var success = vital != null && vital.Ranks >= emote.Min && vital.Ranks <= emote.Max;
                    InqCategory(success ? EmoteCategory.TestSuccess : EmoteCategory.TestFailure, emote);
                }
                break;

            case EmoteType.InqSkillSpecialized:

                if (creature != null)
                {
                    var skill = creature.GetCreatureSkill((Skill)emote.Stat);
                    InqProperty(skill.AdvancementClass == SkillAdvancementClass.Specialized, emote);
                }
                break;

            case EmoteType.InqSkillStat:

                if (creature != null)
                {
                    var skill   = creature.GetCreatureSkill((Skill)emote.Stat);
                    var success = skill != null && skill.Ranks >= emote.Min && skill.Ranks <= emote.Max;
                    InqCategory(success ? EmoteCategory.TestSuccess : EmoteCategory.TestFailure, emote);
                }
                break;

            case EmoteType.InqSkillTrained:

                if (creature != null)
                {
                    var skill = creature.GetCreatureSkill((Skill)emote.Stat);
                    InqProperty(skill.AdvancementClass == SkillAdvancementClass.Trained || skill.AdvancementClass == SkillAdvancementClass.Specialized, emote);
                }
                break;

            case EmoteType.InqStringStat:

                InqProperty(target.GetProperty((PropertyString)emote.Stat), emote);
                break;

            case EmoteType.InqYesNo:
                ConfirmationManager.ProcessConfirmation(emote.Stat, true);
                break;

            case EmoteType.Invalid:
                break;

            case EmoteType.KillSelf:

                if (player != null)
                {
                    player.Smite(WorldObject);
                }
                break;

            case EmoteType.LocalBroadcast:

                text = Replace(emote.Message, WorldObject, target);
                WorldObject.EnqueueBroadcast(new GameMessageSystemChat(text, ChatMessageType.Broadcast));
                break;

            case EmoteType.LocalSignal:
                break;

            case EmoteType.LockFellow:

                if (player != null && player.Fellowship != null)
                {
                    player.HandleActionFellowshipChangeOpenness(false);
                }
                break;

            case EmoteType.Motion:

                WorldObject.PhysicsObj.DoMotion(emote.Motion, new MovementParameters());
                break;

            case EmoteType.Move:

                if (creature != null)
                {
                    var movement = creature.PhysicsObj.MovementManager.MoveToManager;
                    movement.MoveToPosition(new Physics.Common.Position(emote.Position), new MovementParameters());
                }
                break;

            case EmoteType.MoveHome:

                if (creature != null)
                {
                    var movement = creature.PhysicsObj.MovementManager.MoveToManager;
                    movement.MoveToPosition(new Physics.Common.Position(creature.Home), new MovementParameters());
                }
                break;

            case EmoteType.MoveToPos:

                if (creature != null)
                {
                    var movement = creature.PhysicsObj.MovementManager.MoveToManager;
                    movement.MoveToPosition(new Physics.Common.Position(emote.Position), new MovementParameters());
                }
                break;

            case EmoteType.OpenMe:

                target.Open(WorldObject);
                break;

            case EmoteType.PetCastSpellOnOwner:

                if (WorldObject is Creature)
                {
                    (WorldObject as Creature).CreateCreatureSpell(target.Guid, emote.SpellId);
                }
                break;

            case EmoteType.PhysScript:

                target.PhysicsObj.play_script(emote.PScript, 1.0f);
                break;

            case EmoteType.PopUp:
                ConfirmationManager.AddConfirmation(new Confirmation((ConfirmationType)emote.Stat, emote.Message, WorldObject, target));
                break;

            case EmoteType.RemoveContract:

                if (player != null)
                {
                    player.HandleActionAbandonContract(emote.Stat);
                }
                break;

            case EmoteType.RemoveVitaePenalty:

                if (player != null)
                {
                    player.VitaeCpPool = 0;
                }
                break;

            case EmoteType.ResetHomePosition:

                if (creature != null)
                {
                    target.Home = emote.Position;
                }
                break;

            case EmoteType.Say:

                text = Replace(emote.Message, WorldObject, target);
                if (player != null)
                {
                    player.EnqueueBroadcast(new GameMessageCreatureMessage(text, player.Name, player.Guid.Full, ChatMessageType.Speech));
                }
                break;

            case EmoteType.SetAltRacialSkills:
                break;

            case EmoteType.SetBoolStat:
                target.SetProperty((PropertyBool)emote.Stat, emote.Amount == 0 ? false : true);
                break;

            case EmoteType.SetEyePalette:

                if (creature != null)
                {
                    creature.EyesPaletteDID = (uint)emote.Display;
                }
                break;

            case EmoteType.SetEyeTexture:

                if (creature != null)
                {
                    creature.EyesTextureDID = (uint)emote.Display;
                }
                break;

            case EmoteType.SetFloatStat:
                target.SetProperty((PropertyFloat)emote.Stat, (float)emote.Amount);
                break;

            case EmoteType.SetHeadObject:

                if (creature != null)
                {
                    creature.HeadObjectDID = (uint)emote.Display;
                }
                break;

            case EmoteType.SetHeadPalette:
                break;

            case EmoteType.SetInt64Stat:
                target.SetProperty((PropertyInt)emote.Stat, (int)emote.Amount);
                break;

            case EmoteType.SetIntStat:
                target.SetProperty((PropertyInt)emote.Stat, (int)emote.Amount);
                break;

            case EmoteType.SetMouthPalette:
                break;

            case EmoteType.SetMouthTexture:

                if (creature != null)
                {
                    creature.MouthTextureDID = (uint)emote.Display;
                }
                break;

            case EmoteType.SetMyQuestBitsOff:
                break;

            case EmoteType.SetMyQuestBitsOn:
                break;

            case EmoteType.SetMyQuestCompletions:
                break;

            case EmoteType.SetNosePalette:
                break;

            case EmoteType.SetNoseTexture:

                if (creature != null)
                {
                    creature.NoseTextureDID = (uint)emote.Display;
                }
                break;

            case EmoteType.SetQuestBitsOff:
                break;

            case EmoteType.SetQuestBitsOn:
                break;

            case EmoteType.SetQuestCompletions:
                break;

            case EmoteType.SetSanctuaryPosition:

                if (player != null)
                {
                    player.Sanctuary = emote.Position;
                }
                break;

            case EmoteType.Sound:
                target.EnqueueBroadcast(new GameMessageSound(target.Guid, (Sound)emote.Sound, 1.0f));
                break;

            case EmoteType.SpendLuminance:
                if (player != null)
                {
                    player.SpendLuminance((long)emote.Amount);
                }
                break;

            case EmoteType.StampFellowQuest:
                break;

            case EmoteType.StampMyQuest:
                break;

            case EmoteType.StampQuest:
                break;

            case EmoteType.StartBarber:
                break;

            case EmoteType.StartEvent:

                EventManager.StartEvent(emote.Message);
                break;

            case EmoteType.StopEvent:

                EventManager.StopEvent(emote.Message);
                break;

            case EmoteType.TakeItems:

                if (player != null)
                {
                    wcid = emote.CreateProfile.ClassID;
                    item = WorldObjectFactory.CreateNewWorldObject(wcid);
                    if (item == null)
                    {
                        break;
                    }

                    var success = player.TryConsumeFromInventoryWithNetworking(item, (int)emote.Amount);
                }
                break;

            case EmoteType.TeachSpell:

                if (player != null)
                {
                    player.LearnSpellWithNetworking(emote.SpellId);
                }
                break;

            case EmoteType.TeleportSelf:

                if (WorldObject is Player)
                {
                    (WorldObject as Player).Teleport(emote.Position);
                }
                break;

            case EmoteType.TeleportTarget:

                if (player != null)
                {
                    player.Teleport(emote.Position);
                }
                break;

            case EmoteType.Tell:

                text = Replace(emote.Message, WorldObject, target);
                if (player != null)
                {
                    player.Session.Network.EnqueueSend(new GameMessageSystemChat(text, ChatMessageType.Tell));
                }
                break;

            case EmoteType.TellFellow:

                text = Replace(emote.Message, WorldObject, target);
                if (player != null)
                {
                    var fellowship = player.Fellowship;
                    if (fellowship != null)
                    {
                        player.Session.Network.EnqueueSend(new GameMessageSystemChat(text, ChatMessageType.Tell));
                    }
                    else
                    {
                        foreach (var fellow in fellowship.FellowshipMembers)
                        {
                            player.Session.Network.EnqueueSend(new GameMessageSystemChat(text, ChatMessageType.Tell));
                        }
                    }
                }
                break;

            case EmoteType.TextDirect:

                text = Replace(emote.Message, WorldObject, target);
                if (player != null)
                {
                    player.Session.Network.EnqueueSend(new GameMessageSystemChat(text, ChatMessageType.AdminTell));
                }
                break;

            case EmoteType.Turn:

                var mvp = new MovementParameters();
                mvp.DesiredHeading = new AFrame(emote.Frame).get_heading();

                // increment animation sequence
                WorldObject.PhysicsObj.LastMoveWasAutonomous = false;
                WorldObject.PhysicsObj.cancel_moveto();
                WorldObject.PhysicsObj.TurnToHeading(mvp);
                break;

            case EmoteType.TurnToTarget:

                WorldObject.PhysicsObj.TurnToObject(target.Guid.Full, new MovementParameters());
                break;

            case EmoteType.UntrainSkill:

                if (player != null)
                {
                    player.UntrainSkill((Skill)emote.Stat, 1);
                }
                break;

            case EmoteType.UpdateFellowQuest:
                break;

            case EmoteType.UpdateMyQuest:
                break;

            case EmoteType.UpdateQuest:
                break;

            case EmoteType.WorldBroadcast:

                text    = Replace(emote.Message, WorldObject, target);
                players = PlayerManager.GetAllOnline();
                foreach (var _player in players)
                {
                    _player.Session.Network.EnqueueSend(new GameMessageSystemChat(text, ChatMessageType.WorldBroadcast));
                }
                break;
            }
        }
示例#4
0
        /// <summary>
        /// Threaded task created when performing a server shutdown
        /// </summary>
        private static void ShutdownServer()
        {
            var shutdownTime = DateTime.UtcNow.AddSeconds(ShutdownInterval);

            ShutdownTime = shutdownTime;

            var lastNoticeTime = DateTime.UtcNow;

            // wait for shutdown interval to expire
            while (shutdownTime != DateTime.MinValue && shutdownTime >= DateTime.UtcNow)
            {
                // this allows the server shutdown to be canceled
                if (!ShutdownInitiated)
                {
                    // reset shutdown details
                    string shutdownText = $"The server has canceled the shutdown procedure @ {DateTime.UtcNow} UTC";
                    log.Info(shutdownText);

                    // special text
                    foreach (var player in PlayerManager.GetAllOnline())
                    {
                        player.Session.WorldBroadcast(shutdownText);
                    }

                    // break function
                    return;
                }

                lastNoticeTime = NotifyPlayersOfPendingShutdown(lastNoticeTime, shutdownTime.AddSeconds(1));

                Thread.Sleep(10);
            }

            ShutdownInProgress = true;

            PropertyManager.ResyncVariables();
            PropertyManager.StopUpdating();

            log.Debug("Logging off all players...");

            // logout each player
            foreach (var player in PlayerManager.GetAllOnline())
            {
                player.Session.LogOffPlayer(true);
            }

            // Wait for all players to log out
            var logUpdateTS = DateTime.MinValue;
            int playerCount;

            while ((playerCount = PlayerManager.GetOnlineCount()) > 0)
            {
                logUpdateTS = LogStatusUpdate(logUpdateTS, $"Waiting for {playerCount} player{(playerCount > 1 ? "s" : "")} to log off...");
                Thread.Sleep(10);
            }

            log.Debug("Disconnecting all sessions...");

            // disconnect each session
            NetworkManager.DisconnectAllSessionsForShutdown();

            // Wait for all sessions to drop out
            logUpdateTS = DateTime.MinValue;
            int sessionCount;

            while ((sessionCount = NetworkManager.GetSessionCount()) > 0)
            {
                logUpdateTS = LogStatusUpdate(logUpdateTS, $"Waiting for {sessionCount} session{(sessionCount > 1 ? "s" : "")} to disconnect...");
                Thread.Sleep(10);
            }

            log.Debug("Adding all landblocks to destruction queue...");

            // Queue unloading of all the landblocks
            // The actual unloading will happen in WorldManager.UpdateGameWorld
            LandblockManager.AddAllActiveLandblocksToDestructionQueue();

            // Wait for all landblocks to unload
            logUpdateTS = DateTime.MinValue;
            int landblockCount;

            while ((landblockCount = LandblockManager.GetLoadedLandblocks().Count) > 0)
            {
                logUpdateTS = LogStatusUpdate(logUpdateTS, $"Waiting for {landblockCount} loaded landblock{(landblockCount > 1 ? "s" : "")} to unload...");
                Thread.Sleep(10);
            }

            log.Debug("Stopping world...");

            // Disabled thread update loop
            WorldManager.StopWorld();

            // Wait for world to end
            logUpdateTS = DateTime.MinValue;
            while (WorldManager.WorldActive)
            {
                logUpdateTS = LogStatusUpdate(logUpdateTS, "Waiting for world to stop...");
                Thread.Sleep(10);
            }

            log.Info("Saving OfflinePlayers that have unsaved changes...");
            PlayerManager.SaveOfflinePlayersWithChanges();

            // Wait for the database queue to empty
            logUpdateTS = DateTime.MinValue;
            int shardQueueCount;

            while ((shardQueueCount = DatabaseManager.Shard.QueueCount) > 0)
            {
                logUpdateTS = LogStatusUpdate(logUpdateTS, $"Waiting for database queue ({shardQueueCount}) to empty...");
                Thread.Sleep(10);
            }

            // Write exit to console/log
            log.Info($"Exiting at {DateTime.UtcNow}");

            // System exit
            Environment.Exit(Environment.ExitCode);
        }
示例#5
0
        /// <summary>
        /// Threaded task created when performing a server shutdown
        /// </summary>
        private static void ShutdownServer()
        {
            var shutdownTime = DateTime.UtcNow.AddSeconds(ShutdownInterval);

            ShutdownTime = shutdownTime;

            var lastNoticeTime = DateTime.UtcNow;

            // wait for shutdown interval to expire
            while (shutdownTime != DateTime.MinValue && shutdownTime >= DateTime.UtcNow)
            {
                // this allows the server shutdown to be canceled
                if (!ShutdownInitiated)
                {
                    // reset shutdown details
                    string shutdownText = $"The server shut down has been cancelled @ {DateTime.Now} ({DateTime.UtcNow} UTC)";
                    log.Info(shutdownText);

                    // special text
                    foreach (var player in PlayerManager.GetAllOnline())
                    {
                        player.Session.WorldBroadcast($"Broadcast from System> ATTENTION - This Asheron's Call Server shut down has been cancelled.");
                    }

                    // break function
                    return;
                }

                lastNoticeTime = NotifyPlayersOfPendingShutdown(lastNoticeTime, shutdownTime.AddSeconds(1));

                Thread.Sleep(10);
            }

            ShutdownInProgress = true;

            PropertyManager.ResyncVariables();
            PropertyManager.StopUpdating();

            WorldManager.EnqueueAction(new ActionEventDelegate(() =>
            {
                log.Debug("Logging off all players...");

                // logout each player
                foreach (var player in PlayerManager.GetAllOnline())
                {
                    player.Session.LogOffPlayer(true);
                }
            }));

            // Wait for all players to log out
            var logUpdateTS = DateTime.MinValue;
            int playerCount;
            var playerLogoffStart = DateTime.UtcNow;

            while ((playerCount = PlayerManager.GetOnlineCount()) > 0)
            {
                logUpdateTS = LogStatusUpdate(logUpdateTS, $"Waiting for {playerCount} player{(playerCount > 1 ? "s" : "")} to log off...");
                Thread.Sleep(10);
                if (playerCount > 0 && DateTime.UtcNow - playerLogoffStart > TimeSpan.FromMinutes(5))
                {
                    playerLogoffStart = DateTime.UtcNow;
                    log.Warn($"5 minute log off failsafe reached and there are {playerCount} player{(playerCount > 1 ? "s" : "")} still online.");
                    foreach (var player in PlayerManager.GetAllOnline())
                    {
                        log.Warn($"Player {player.Name} (0x{player.Guid}) appears to be stuck in world and unable to log off normally. Requesting Forced Logoff...");
                        player.ForcedLogOffRequested = true;
                        player.ForceLogoff();
                    }
                }
            }

            WorldManager.EnqueueAction(new ActionEventDelegate(() =>
            {
                log.Debug("Disconnecting all sessions...");

                // disconnect each session
                NetworkManager.DisconnectAllSessionsForShutdown();
            }));

            // Wait for all sessions to drop out
            logUpdateTS = DateTime.MinValue;
            int sessionCount;

            while ((sessionCount = NetworkManager.GetAuthenticatedSessionCount()) > 0)
            {
                logUpdateTS = LogStatusUpdate(logUpdateTS, $"Waiting for {sessionCount} authenticated session{(sessionCount > 1 ? "s" : "")} to disconnect...");
                Thread.Sleep(10);
            }

            log.Debug("Adding all landblocks to destruction queue...");

            // Queue unloading of all the landblocks
            // The actual unloading will happen in WorldManager.UpdateGameWorld
            LandblockManager.AddAllActiveLandblocksToDestructionQueue();

            // Wait for all landblocks to unload
            logUpdateTS = DateTime.MinValue;
            int landblockCount;

            while ((landblockCount = LandblockManager.GetLoadedLandblocks().Count) > 0)
            {
                logUpdateTS = LogStatusUpdate(logUpdateTS, $"Waiting for {landblockCount} loaded landblock{(landblockCount > 1 ? "s" : "")} to unload...");
                Thread.Sleep(10);
            }

            log.Debug("Stopping world...");

            // Disabled thread update loop
            WorldManager.StopWorld();

            // Wait for world to end
            logUpdateTS = DateTime.MinValue;
            while (WorldManager.WorldActive)
            {
                logUpdateTS = LogStatusUpdate(logUpdateTS, "Waiting for world to stop...");
                Thread.Sleep(10);
            }

            log.Info("Saving OfflinePlayers that have unsaved changes...");
            PlayerManager.SaveOfflinePlayersWithChanges();

            // Wait for the database queue to empty
            logUpdateTS = DateTime.MinValue;
            int shardQueueCount;

            while ((shardQueueCount = DatabaseManager.Shard.QueueCount) > 0)
            {
                logUpdateTS = LogStatusUpdate(logUpdateTS, $"Waiting for database queue ({shardQueueCount}) to empty...");
                Thread.Sleep(10);
            }

            // Write exit to console/log
            log.Info($"Exiting at {DateTime.UtcNow}");

            // System exit
            Environment.Exit(Environment.ExitCode);
        }