1. Hi!

    So in my GUIAnnouncements plugin I am currently in the process of adding a feature to support automatic restart announcements, via restart times added to the config for example:

    Code:
        "RestartTimes": [
          "20:00:00",
          "08:00:00"
        ],
    What I will need to do is when the plugin is loaded, determine which of these times is next and store that in a global variable such as "DateTime NextRestart;". Then I need to check every second what the time is and how much time is left until the next restart and broadcast the time left every hour until 30 minutes are left, 15 then 10 then 5 then 60 seconds at which point it will countdown from 60.

    The main obstacle I am having is figuring out which restart time is next and how to get the difference if say it is 21:00:00 and the next restart is the next day at 08:00:00 (baring in mind the date is never specified so it would be viewed that, that time is already gone).

    This is kind of what I have worked up already on the path to working something out (some of it obviously won't work how I want it to):
    Code:
            DateTime NextRestart;        void OnServerInitialized() //Convert config restart time list into DateTime type then call RestartAnnouncements() to check every second what if anything needs to be announced
            {
                if (restartAnnouncements)
                {
                    List<string> restartTimes = ConvertList(Config.Get("Automatic Announcements", "RestartTimes"));
                    List<DateTime> DateTimes = restartTimes.Select(date => DateTime.Parse(date)).ToList();
                    CompareDateTimes(DateTimes);
                    RealTimeTimer = timer.Repeat(1, 0, () =>
                    {
                            RestartAnnouncements();
                    });
                }
            }        void CompareDateTimes(List<DateTime> DateTimes) //Find out when the next restart is here
            {
                var e = DateTimes.GetEnumerator();
                for (var i = 0; e.MoveNext(); i++)
                {
                    int result = DateTime.Compare(DateTime.Now, e.Current);
                    if (result < 0)
                    {
                        NextRestart = e.Current;
                        Puts("Current time " + DateTime.Now.ToString());
                        Puts("Next restart " + NextRestart.ToString());
                        TimeSpan timeLeft = DateTime.Now.Subtract(NextRestart);
                        Puts("Time left until restart " + timeLeft.ToString());
                        return;
                    }
                    if (result > 0)
                    {
                        NextRestart = e.Current.AddDays(1);
                        Puts("Current time " + DateTime.Now.ToString());
                        Puts("Next restart " + NextRestart.ToString());
                        TimeSpan timeLeft = DateTime.Now.Subtract(NextRestart);
                        Puts("Time left until restart " + timeLeft.ToString());
                        return;
                    }
                }
            }        void RestartAnnouncements() //Check here if anything needs to be announced, if so figure out what and announce it
            {
                if (NextRestart == DateTime.Now)
                    return;
                TimeSpan timeLeft = DateTime.Now.Subtract(NextRestart);
                int sixtySeconds = 60;
                int hoursLeft = timeLeft.Hours;
                int minutesLeft = timeLeft.Minutes;
                int secondsLeft = timeLeft.Seconds;
                string timeLeftString = String.Empty;
                if (hoursLeft > 0)
                    timeLeftString = timeLeftString + hoursLeft + " hours";
                if (minutesLeft > 0 && hoursLeft < 1)
                    timeLeftString = timeLeftString + minutesLeft + " minutes";
                if (secondsLeft > 0 && minutesLeft < 1)
                    timeLeftString = timeLeftString + secondsLeft + " seconds";
                if (timeLeft <= new TimeSpan(00, 01, 00))
                {
                    SixtySecondsTimer = timer.Repeat(1, 60, () =>
                        {
                            CreateMsgGUI(Lang("RestartAnnouncementsFormat").Replace("{time}", sixtySeconds.ToString() + " seconds"), bannerTintGrey, textWhite);
                            sixtySeconds = sixtySeconds -1;
                        });
                }
                else
                {
                    Puts(Lang("RestartAnnouncementsFormat").Replace("{time}", timeLeftString));
                    CreateMsgGUI(Lang("RestartAnnouncementsFormat").Replace("{time}", timeLeftString), bannerTintGrey, textWhite);
                }
            }
    So I was just wandering if any one might be able to help with coming up with a strategy of doing this? I'm stuck at the moment trying to figure out a way to work out what time is next and getting the time left.


    Cheers!
     
    Last edited by a moderator: Jul 3, 2016
  2. In my timer plugin you can see a example of this. Every second it saves the time left on the timer to a variable which is accessed throughout the plugin. When it detects it is at zero then it ends the timer. I simply just made a timer repeat for (x) times(the amount of seconds)and had it repeat every second
    [DOUBLEPOST=1467586085][/DOUBLEPOST]So you could do like if (currenttime) == 2100 do stuff. Or if that time is in a list then do stuff. So like if TimeAnnounce.Contains(time) then do stuff.
    [DOUBLEPOST=1467586605][/DOUBLEPOST]So for example:
    Code:
            void Test()
            {
                var time1 = 2100
                var time2 = 800
                var activetime = 0;            timer.Repeat(1, 2400, () =>
                {
                    activetime = activetime + 1;
                    if(activetime == 2100)
                    {
                        //Announce 2100seconds till restart
                        PrintToChat("There is: "+activetime+"(s) till restart!");
                    } 
                    else if(activetime == 800)
                    {
                        PrintToChat("There is: "+activetime+"(s) till restart!")
                    }
                    else if(activetime == 60 || activetime < 60 && activetime > 0)
                    {
                        PrintToChat("Restart in: "+activetime+" seconds");
                        timer.Repeat(1, 60, () =>
                        {
                            PrintToChat("Restart in: "+activetime+" seconds");
                        });
                    }
                    else if(activetime == 0)
                    {
                        PrintToChat("Restarting...");
                        //Restart command here//
                    }
                    else
                    {
                        return;
                    }           
                });
            }
    Im sure there is a different way not using timer.repeat or timer.once however.
     
    Last edited by a moderator: Jul 3, 2016
  3. Cheers @DylanSMR
    The thing is that the plugin may not always be loaded as well as reloaded during the server's up time. While I can quite easily just check every second if the time is currently one in the config then do a restart, figuring out the time left before a restart at any point is what I can't figure out. If I knew a way of checking how much time is left, then I could just create a bunch of if statements telling it what to do. So if I was to give the option to restart every xxx seconds in the config it would lead to inconsistent restart times where people prefer to have it restarting at a specific time, every time.
     
  4. Ah ok. I think ive seen someone use the datetime.now.subtract. I cannot remember however have you checked the restart plugin that exists currently?
     
  5. I have looked at them, but unfortunately none do quite what I am looking for. DateTime.Now.Subtract is kind of what I thought could do it, but it doesn't help when the date it not known because then everything is viewed to be the same date.

    I was just thinking of a strategy perhaps something like this:
    Find if a restart is later than current time, find difference then add to new DateTime TimeSpan dictionary.
    Find if a restart is earlier than current time and add 1 day, find difference then add to the new DateTime TimeSpan dictionary.
    Find the closest DateTime to DateTime.Now by finding the lowest TimeSpan value in dictionary.
    Use that DateTime key as NextRestartTime?

    I should only have to do that once in OnServerInitialized then every second calculate the difference between the found NextRestartTime and announce how long is left when appropriate.
     
    Last edited by a moderator: Jul 4, 2016
  6. Sounds like it could work.
     
  7. Got it!

    Code:
    [Oxide] 19:18 [Info] [GUIAnnouncements] Next restart is at 5.08:00:00
    [Oxide] 19:18 [Info] [GUIAnnouncements] Time until next restart is 12:41:15.0904160

    Code:
            private Dictionary<DateTime, TimeSpan> CalcNextRestartDict = new Dictionary<DateTime, TimeSpan>();
            private DateTime NextRestart;        void GetNextRestart(List<DateTime> DateTimes)
            {
                var e = DateTimes.GetEnumerator();
                for (var i = 0; e.MoveNext(); i++)
                {
                    if (DateTime.Compare(DateTime.Now, e.Current) < 0)
                    {
                        CalcNextRestartDict.Add(e.Current, e.Current.Subtract(DateTime.Now));
                    }
                    if (DateTime.Compare(DateTime.Now, e.Current) > 0)
                    {
                        CalcNextRestartDict.Add(e.Current.AddDays(1), e.Current.AddDays(1).Subtract(DateTime.Now));
                    }
                }
                NextRestart = CalcNextRestartDict.Aggregate((l, r) => l.Value < r.Value ? l : r).Key;
                Puts("Next restart is at " + NextRestart.ToString());
                Puts("Time until next restart is " + NextRestart.Subtract(DateTime.Now).ToString());
            }
    
    Once I get it all working I can clean up the code.
     
    Last edited by a moderator: Jul 4, 2016
  8. Nice job!
     
  9. Yep I got it working pretty darn spot on. With all the announcements happening only when they are supposed to and with the correct time left.