diff --git a/.gitignore b/.gitignore
index a53bb84..28c4ff8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,6 @@
*.zip
-_releases
\ No newline at end of file
+_releases
+.vs
+.sln
+bin
+obj
\ No newline at end of file
diff --git a/FiveM_TimeSync.sln b/FiveM_TimeSync.sln
new file mode 100644
index 0000000..0207f82
--- /dev/null
+++ b/FiveM_TimeSync.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FiveM_TimeSync", "FiveM_TimeSync\FiveM_TimeSync.csproj", "{E43819C4-7F54-408A-B097-794CBD245BAD}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FiveM_TimeSyncServer", "FiveM_TimeSyncServer\FiveM_TimeSyncServer.csproj", "{A4E0CA53-9DCD-453F-83CD-3F7AB0F25807}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {E43819C4-7F54-408A-B097-794CBD245BAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E43819C4-7F54-408A-B097-794CBD245BAD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E43819C4-7F54-408A-B097-794CBD245BAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E43819C4-7F54-408A-B097-794CBD245BAD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A4E0CA53-9DCD-453F-83CD-3F7AB0F25807}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A4E0CA53-9DCD-453F-83CD-3F7AB0F25807}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A4E0CA53-9DCD-453F-83CD-3F7AB0F25807}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A4E0CA53-9DCD-453F-83CD-3F7AB0F25807}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {6433BD9B-8AB9-4772-BC1B-9C06B796AC4F}
+ EndGlobalSection
+EndGlobal
diff --git a/FiveM_TimeSync/Client.cs b/FiveM_TimeSync/Client.cs
new file mode 100644
index 0000000..ed33e97
--- /dev/null
+++ b/FiveM_TimeSync/Client.cs
@@ -0,0 +1,13 @@
+using VinaFrameworkClient.Core;
+using FiveM_TimeSync.Modules;
+
+namespace FiveM_TimeSync
+{
+ public class Client : BaseClient
+ {
+ public Client()
+ {
+ AddModule(typeof(TimeSyncModule));
+ }
+ }
+}
diff --git a/FiveM_TimeSync/FiveM_TimeSync.csproj b/FiveM_TimeSync/FiveM_TimeSync.csproj
new file mode 100644
index 0000000..ec65cf6
--- /dev/null
+++ b/FiveM_TimeSync/FiveM_TimeSync.csproj
@@ -0,0 +1,62 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {E43819C4-7F54-408A-B097-794CBD245BAD}
+ Library
+ Properties
+ FiveM_TimeSync
+ FiveM_TimeSync.net
+ v4.5.2
+ 512
+ true
+
+
+ false
+ none
+ false
+ ..\..\_resources\fivemtimesync\
+ DEBUG;TRACE
+ prompt
+ 4
+ Off
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ ..\..\..\..\FiveM.app\citizen\clr2\lib\mono\4.5\CitizenFX.Core.dll
+ False
+
+
+
+
+
+
+
+
+
+
+ False
+ ..\..\_dependencies\VinaFrameworkClient.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/FiveM_TimeSync/Modules/TimeSyncModule.cs b/FiveM_TimeSync/Modules/TimeSyncModule.cs
new file mode 100644
index 0000000..60836c5
--- /dev/null
+++ b/FiveM_TimeSync/Modules/TimeSyncModule.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Threading.Tasks;
+
+using CitizenFX.Core.Native;
+
+using VinaFrameworkClient.Core;
+
+namespace FiveM_TimeSync.Modules
+{
+ public class TimeSyncModule : Module
+ {
+ public TimeSyncModule(Client client) : base(client)
+ {
+ script.AddEvent("TimeSync.UpdateDateTime", new Action(OnUpdateDateTime));
+ script.AddTick(OverrideTime);
+ }
+
+ #region ACCESSORS
+
+ public DateTime CurrentDate
+ {
+ get
+ {
+ return lastServerTime.AddMilliseconds(timeElapsed);
+ }
+ }
+
+ public TimeSpan CurrentTime
+ {
+ get
+ {
+ return CurrentDate.TimeOfDay;
+ }
+ }
+
+ private double timeElapsed
+ {
+ get
+ {
+ return DateTime.Now.Subtract(startingDate).TotalMilliseconds * timeRate;
+ }
+ }
+
+ #endregion
+ #region VARIABLES
+
+ private int timeRate;
+ private DateTime startingDate;
+ private DateTime lastServerTime;
+
+ #endregion
+ #region MODULE EVENTS
+
+ private void OnUpdateDateTime(int newTimeRate, long currentTicks)
+ {
+ timeRate = newTimeRate;
+ startingDate = DateTime.Now;
+ lastServerTime = new DateTime(currentTicks);
+
+ script.Log($"Received update from server [TimeRate: {timeRate}, Server Time: ${lastServerTime}]");
+ }
+
+ #endregion
+ #region MODULES TICKS
+
+ private async Task OverrideTime()
+ {
+ while (true)
+ {
+ await Client.Delay(33);
+
+ if (startingDate == null || lastServerTime == null) continue;
+
+ API.NetworkOverrideClockTime(CurrentTime.Hours, CurrentTime.Minutes, CurrentTime.Seconds);
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/FiveM_TimeSync/Properties/AssemblyInfo.cs b/FiveM_TimeSync/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..47df24f
--- /dev/null
+++ b/FiveM_TimeSync/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("FiveM_TimeSync")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("FiveM_TimeSync")]
+[assembly: AssemblyCopyright("Copyright © VinaStar 2020")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("e43819c4-7f54-408a-b097-794cbd245bad")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/FiveM_TimeSyncServer/FiveM_TimeSyncServer.csproj b/FiveM_TimeSyncServer/FiveM_TimeSyncServer.csproj
new file mode 100644
index 0000000..4fde351
--- /dev/null
+++ b/FiveM_TimeSyncServer/FiveM_TimeSyncServer.csproj
@@ -0,0 +1,62 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {A4E0CA53-9DCD-453F-83CD-3F7AB0F25807}
+ Library
+ Properties
+ FiveM_TimeSyncServer
+ FiveM_TimeSyncServer.net
+ v4.5.2
+ 512
+ true
+
+
+ false
+ none
+ false
+ ..\..\_resources\fivemtimesync\
+ DEBUG;TRACE
+ prompt
+ 4
+ Off
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ ..\..\..\fivem_server\citizen\clr2\lib\mono\4.5\CitizenFX.Core.dll
+ False
+
+
+
+
+
+
+
+
+
+
+ False
+ ..\..\_dependencies\VinaFrameworkServer.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/FiveM_TimeSyncServer/Modules/TimeSyncModule.cs b/FiveM_TimeSyncServer/Modules/TimeSyncModule.cs
new file mode 100644
index 0000000..a0ea5eb
--- /dev/null
+++ b/FiveM_TimeSyncServer/Modules/TimeSyncModule.cs
@@ -0,0 +1,217 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+
+using CitizenFX.Core;
+using CitizenFX.Core.Native;
+
+using VinaFrameworkServer.Core;
+
+namespace FiveM_TimeSyncServer.Modules
+{
+ public class TimeSyncModule : Module
+ {
+ public TimeSyncModule(Server server) : base(server)
+ {
+ endingDate = LoadCurrentTime();
+ lastServerTime = DateTime.Now;
+
+ script.AddTick(NetworkResync);
+ script.AddTick(AutosaveTime);
+ script.AddTick(PeriodicConsolePrint);
+
+ script.SetExport("CurrentDateTicks", new Func(ExportCurrentDateTicks));
+ }
+
+ #region ACCESSORS
+
+ public DateTime RealDate
+ {
+ get
+ {
+ return DateTime.Now;
+ }
+ }
+
+ public TimeSpan RealTime
+ {
+ get
+ {
+ return RealDate.TimeOfDay;
+ }
+ }
+
+ public DateTime CurrentDate
+ {
+ get
+ {
+ return endingDate.AddMilliseconds(timeElapsed);
+ }
+ }
+
+ public TimeSpan CurrentTime
+ {
+ get
+ {
+ return CurrentDate.TimeOfDay;
+ }
+ }
+
+ private double timeElapsed
+ {
+ get
+ {
+ return DateTime.Now.Subtract(lastServerTime).TotalMilliseconds * timeRate;
+ }
+ }
+
+ #endregion
+ #region VARIABLES
+
+ private bool verbose;
+ private bool printEnabled;
+ private string printFormat;
+ private int printDelay;
+ private int clientUpdateDelay;
+ private int timeRate;
+ private DateTime endingDate;
+ private DateTime lastServerTime;
+
+ #endregion
+ #region BASE EVENTS
+
+ protected override void OnModuleInitialized()
+ {
+ // Print more informations
+ verbose = API.GetConvarInt("timesync_network_verbose", 0) == 0;
+
+ // Peridically print current time
+ printEnabled = API.GetConvarInt("timesync_console_print_time", 0) == 0;
+
+ // Console Print Time Format
+ printFormat = API.GetConvar("timesync_console_print_format", "MMMM d yyyy, HH:mm:ss tt");
+
+ // Console Print Time Delay
+ printDelay = API.GetConvarInt("timesync_console_print_delay", 1000 * 60 * 5);
+
+ // Sync players every 10 secs
+ clientUpdateDelay = API.GetConvarInt("timesync_update_delay", 60000);
+
+ // 10 x realtime
+ timeRate = API.GetConvarInt("timesync_timerate", 1);
+
+ Debug.WriteLine($@"
+=====================================
+FIVEM TIME SYNC SETTINGS:
+=====================================
+ timesync_console_print = {printEnabled}
+ timesync_console_print_format = {printFormat}
+ timesync_console_print_delay (ms) = {printDelay}
+ timesync_update_delay (ms) = {clientUpdateDelay}
+ timesync_timerate (1sec * timerate) = {timeRate}
+ Current Date = {CurrentDate.ToString(printFormat)}
+=====================================");
+ }
+
+ protected override void OnPlayerConnecting(Player player)
+ {
+
+ }
+
+ protected override void OnPlayerDropped(Player player, string reason)
+ {
+
+ }
+
+ protected override void OnPlayerClientInitialized(Player player)
+ {
+ UpdatePlayerDateTime(player);
+ }
+
+ #endregion
+ #region MODULE TICKS
+
+ private async Task NetworkResync()
+ {
+ await Server.Delay(clientUpdateDelay);
+
+ UpdatePlayerDateTime();
+ }
+
+ private async Task AutosaveTime()
+ {
+ await Server.Delay(30000);
+
+ await SaveCurrentTime();
+ }
+
+ private async Task PeriodicConsolePrint()
+ {
+ await Server.Delay(printDelay);
+
+ if (!printEnabled) return;
+
+ script.Log($@"SERVER CURRENT TIME: {CurrentDate.ToString(printFormat)}");
+ }
+
+ #endregion
+ #region MODULE METHODS
+
+ private void UpdatePlayerDateTime(Player player = null)
+ {
+ if (player != null)
+ {
+ Server.TriggerClientEvent(player, "TimeSync.UpdateDateTime", timeRate, CurrentDate.Ticks);
+ if (verbose) script.Log($"FiveM TimeSync syncing player ${player.Name} time!");
+ }
+ else
+ {
+ if (API.GetNumPlayerIndices() > 0)
+ {
+ Server.TriggerClientEvent("TimeSync.UpdateDateTime", timeRate, CurrentDate.Ticks);
+ if (verbose) script.Log($"FiveM TimeSync syncing all players time!");
+ }
+ else if (verbose) script.Log($"FiveM TimeSync no online players, skipping syncing...");
+ }
+ }
+
+ private DateTime LoadCurrentTime()
+ {
+ try
+ {
+ string fileData = File.ReadAllText("server_time.txt");
+ script.Log("Loaded time from server_time.txt");
+ return DateTime.Parse(fileData);
+ }
+ catch (Exception exception)
+ {
+ script.Log("Could not get time from server_time.txt, starting with real time.");
+ }
+
+ return DateTime.Now;
+ }
+
+ private async Task SaveCurrentTime()
+ {
+ try
+ {
+ using (StreamWriter writer = File.CreateText("server_time.txt"))
+ {
+ await writer.WriteAsync(CurrentDate.ToString());
+ writer.Close();
+ }
+ }
+ catch (Exception exception)
+ {
+ script.LogError(exception);
+ }
+ }
+
+ private long ExportCurrentDateTicks()
+ {
+ return CurrentDate.Ticks;
+ }
+
+ #endregion
+ }
+}
diff --git a/FiveM_TimeSyncServer/Properties/AssemblyInfo.cs b/FiveM_TimeSyncServer/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..f7794af
--- /dev/null
+++ b/FiveM_TimeSyncServer/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("FiveM_TimeSyncServer")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("FiveM_TimeSyncServer")]
+[assembly: AssemblyCopyright("Copyright © VinaStar 2020")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("a4e0ca53-9dcd-453f-83cd-3f7ab0f25807")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/FiveM_TimeSyncServer/Server.cs b/FiveM_TimeSyncServer/Server.cs
new file mode 100644
index 0000000..24707fe
--- /dev/null
+++ b/FiveM_TimeSyncServer/Server.cs
@@ -0,0 +1,13 @@
+using VinaFrameworkServer.Core;
+using FiveM_TimeSyncServer.Modules;
+
+namespace FiveM_TimeSyncServer
+{
+ public class Server : BaseServer
+ {
+ public Server()
+ {
+ AddModule(typeof(TimeSyncModule));
+ }
+ }
+}
diff --git a/Resources/fivemtimesync/FiveM_TimeSync.net.dll b/Resources/fivemtimesync/FiveM_TimeSync.net.dll
deleted file mode 100644
index 1de6668..0000000
Binary files a/Resources/fivemtimesync/FiveM_TimeSync.net.dll and /dev/null differ
diff --git a/Resources/fivemtimesync/FiveM_TimeSyncServer.net.dll b/Resources/fivemtimesync/FiveM_TimeSyncServer.net.dll
deleted file mode 100644
index 90ca7c5..0000000
Binary files a/Resources/fivemtimesync/FiveM_TimeSyncServer.net.dll and /dev/null differ
diff --git a/Resources/fivemtimesync/__resource.lua b/Resources/fivemtimesync/__resource.lua
deleted file mode 100644
index 0f33155..0000000
--- a/Resources/fivemtimesync/__resource.lua
+++ /dev/null
@@ -1,2 +0,0 @@
-client_script 'FiveM_TimeSync.net.dll'
-server_script 'FiveM_TimeSyncServer.net.dll'
\ No newline at end of file