diff --git a/README.md b/README.md index 621d055..effde5a 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,5 @@ # Tick Manager Constant application tick rate library + + Usage + diff --git a/TickManager.csproj b/TickManager.csproj new file mode 100644 index 0000000..5fe1fc7 --- /dev/null +++ b/TickManager.csproj @@ -0,0 +1,8 @@ + + + + netcoreapp3.1 + Library + + + diff --git a/src/TickClock.cs b/src/TickClock.cs new file mode 100644 index 0000000..5dcb223 --- /dev/null +++ b/src/TickClock.cs @@ -0,0 +1,42 @@ +using Microsoft.Win32; +using System; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; +using System.Security; + +namespace TickManager +{ + /// + /// Clock that calculates tick time + /// + public class TickClock + { + /// + /// The ammount of ticks a millisecond has + /// + internal const double TicksPerMillisecond = 10000; + + /// + /// Internal application start timestamp + /// + internal double startTimeStamp; + + /// + /// Resets the TickClock + /// + public void Reset() + { + startTimeStamp = TickHelper.GetCurrentTimestamp(); + } + + /// + /// Register an application tick + /// + /// The amount of time the application took to register a tick + public double Tick() + { + long currentTimestamp = TickHelper.GetCurrentTimestamp(); + return (currentTimestamp - startTimeStamp) / TicksPerMillisecond; + } + } +} \ No newline at end of file diff --git a/src/TickHelper.cs b/src/TickHelper.cs new file mode 100644 index 0000000..b1d4439 --- /dev/null +++ b/src/TickHelper.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; +using System.Text; + +namespace TickManager +{ + internal static class NativeMethods + { + [DllImport("kernel32.dll")] + [ResourceExposure(ResourceScope.None)] + public static extern bool QueryPerformanceCounter(out long value); + } + + /// + /// Helper functions + /// + public static class TickHelper + { + /// + /// Convert ticks per second to milliseconds per tick + /// + /// Ticks per second + /// Milliseconds per tick + public static double TpsToMspt(double tps) + { + return 1D / tps * 1000; + } + + /// + /// Converts milliseconds per tick to ticks per second + /// + /// Milliseconds per tick + /// Ticks per second + public static double MsptToTps(double mspt) + { + return 1D / mspt * 1000; + } + + internal static long GetCurrentTimestamp() + { + long timestamp; + + // took it from Stopwatch + // maybe find a better way to get the current timestamp + NativeMethods.QueryPerformanceCounter(out timestamp); + return timestamp; + } + } +} diff --git a/src/TickManager.cs b/src/TickManager.cs new file mode 100644 index 0000000..6f330a0 --- /dev/null +++ b/src/TickManager.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace TickManager +{ + /// + /// Handles ticking for an application + /// + public class TickManager + { + /// + /// The frequency the application should be running at + /// + internal double internalFrequency; + + /// + /// Variable to store the milliseconds each tick should take + /// + internal double msptInternal; + + /// + /// Tick clock object + /// + internal TickClock tc = new TickClock(); + + /// + /// The frequency your application will tick + /// + public int Frequency + { + get => (int)internalFrequency; + set + { + // Tries to get an exact aproximation to the integer because Math... + internalFrequency = value + 0.001; + msptInternal = TickHelper.TpsToMspt(internalFrequency); + } + } + + /// + /// Milliseconds per tick that took to run last tick + /// + public double MSPT { get; private set; } + + /// + /// The ticks per second the server is running at relative to last tick + /// + public double TPS + { + get => TickHelper.MsptToTps(MSPT); + } + + /// + /// Checks if the application can process the same tick relative to the frequency set + /// + /// Whether the application should process the next tick or not + public bool CanTick() + { + double internalMspt = tc.Tick(); + bool canTick = internalMspt > msptInternal; + if (canTick) + { + MSPT = internalMspt; + tc.Reset(); + } + return canTick; + } + } +}