1. Right. Just creating a simple timer to subtract two date times with a class to handle it(will be more advanced in the future) and I seem to be running into a small issue.
    You can see the code here:
    Code:
    // Reference: Newtonsoft.Json
    // Reference: Rust.Data
    using UnityEngine;
    using Oxide.Game.Rust.Cui;
    using System.Collections.Generic;
    using System;namespace Oxide.Plugins
    {
        [Info("ScreenTimer", "DylanSMR", "1.0.7", ResourceId = 1918)]
        [Description("A GUI timer.")]
        class ScreenTimer : RustPlugin
        { 
            static List<Timer> timers = new List<Timer>();
            public class Timer
            {
                public DateTime currentTime;
                public DateTime endTime;            public int days;
                public int hours;
                public int minutes;
                public int seconds;            public string Text;
                public string TextColor;
                public string Command;            public string OutlineColor;
                public string InnerColor;            public Timer(){
                    this.RTimer();
                    timers.Add(this);
                }
                public void RTimer(){
                    TimeSpan span = endTime - currentTime;
                    this.days = span.Days;
                    this.hours = span.Hours;
                    this.minutes = span.Minutes;
                    this.seconds = span.Seconds;
                }
            }
            public void RefreshTimer(Timer t){
                t.RTimer();
                PrintWarning($"Time = Days:{t.days}  -  Hours:{t.hours}  -  Minutes:{t.minutes}  -  Seconds:{t.seconds}");
                if(t.currentTime >= t.endTime){
                    PrintWarning("Time Ended");
                    timers.Remove(t);
                    return;
                }
                timer.Once(1f, () =>
                {
                    if(!(t.currentTime >= t.endTime)){t.currentTime = DateTime.Now; RefreshTimer(t); t.RTimer(); }
                });
            }
            [ConsoleCommand("testtimer")]
            void TestTimer(){
                var timer = new Timer(){
                    currentTime = DateTime.Now,
                    endTime = DateTime.Now.AddSeconds(10),
                };
                PrintWarning("Timer Created");
                RefreshTimer(timer);
            }
        }
    }
    And then the output here when I run "testtimer" in console. Any idea's why it is outputting like that instead of 10,9,8,7,6,5,4,3,2,1,0?
    Code:
    [ScreenTimer] Timer Created
    [ScreenTimer] Time = Days:0  -  Hours:0  -  Minutes:0  -  Seconds:10
    [ScreenTimer] Time = Days:0  -  Hours:0  -  Minutes:0  -  Seconds:8
    [ScreenTimer] Time = Days:0  -  Hours:0  -  Minutes:0  -  Seconds:7
    [ScreenTimer] Time = Days:0  -  Hours:0  -  Minutes:0  -  Seconds:6
    [ScreenTimer] Time = Days:0  -  Hours:0  -  Minutes:0  -  Seconds:5
    [ScreenTimer] Time = Days:0  -  Hours:0  -  Minutes:0  -  Seconds:4
    [ScreenTimer] Time = Days:0  -  Hours:0  -  Minutes:0  -  Seconds:3
    [ScreenTimer] Time = Days:0  -  Hours:0  -  Minutes:0  -  Seconds:2
    [ScreenTimer] Time = Days:0  -  Hours:0  -  Minutes:0  -  Seconds:1
    [ScreenTimer] Time = Days:0  -  Hours:0  -  Minutes:0  -  Seconds:0
    [ScreenTimer] Time = Days:0  -  Hours:0  -  Minutes:0  -  Seconds:0
    [ScreenTimer] Time Ended
     
  2. I haven't tested this, but I suspect your RefreshTimer procedure doesn't need to call t.RTimer() when you call it in the timer.Once loop.
     
  3. Still seems to result in:
    Code:
    [ScreenTimer] Timer Created
    [ScreenTimer] Time = Days:0  -  Hours:0  -  Minutes:0  -  Seconds:10
    [ScreenTimer] Time = Days:0  -  Hours:0  -  Minutes:0  -  Seconds:8
     
  4. Timers are concurrent. Concurrency is not deterministic.
    [DOUBLEPOST=1489371608][/DOUBLEPOST]Here, a more detailed explanation:
    TestTimer is called, you create a new timer with currentTime = DateTime.Now and endTime = DateTime.Now + 10s.
    You call RefreshTimer.
    t.RTimer is called and copies span to RTimer.
    You print the time, time has passed since we created the new timer!
    A new timer is created that fires in *roughly* 1 second.
    Firstly, the time between currentTime and this timer ending isn't actually one second anymore - time passed since we created the timer with DateTime.Now.
    The timer will actually fire in currentTime + delta + 1s, delta being the time your plugin wasted and any of the following inaccuracies.
    Why roughly? Because it is impossible to schedule a timer fully precisely.
    Just a few of the factors affecting this, from less important to more important:
    - CPU clock speed or any other hardware related ticks. If our timer is scheduled between two cycles, we obviously cannot run it at that exact moment.
    This is obviously worsened with hardware slowdown issues like branch missprediction, cache misses etc.
    - OS/C# thread scheduling. If our process/thread isn't scheduled to be allowed to work at the final time, we cannot meet the deadline.
    - Rust tick rate. Iirc Oxide checks every tick (or even less often, depending on the situation) whether your timer finished. This may only be ~10 times per second!
    - Expensive work done in the same tick that your timer is scheduled in. Your timer is done in a specific tick, but some work may kick in right in that tick, for instance some plugin doing a heavy calculation.
    - Garbage collection! This may delay your timer by a couple of seconds!
    We repeat the process. All these inaccuracies add up with every single time we call the timer!
    The actual "end time" you expected to be currentTime + 10s is actually currentTime + delta1 + delta2 + ... + delta10 + 10s.
     
    Last edited by a moderator: Mar 13, 2017