From 83f7cbc96331c38494598fc09bdbaea1d16c367f Mon Sep 17 00:00:00 2001 From: Sardelka9515 Date: Tue, 7 Mar 2023 20:17:53 +0800 Subject: [PATCH] Working client resource system --- Client/Scripting/APIBridge.Generated.cs | 4 +- Client/Scripting/ClientResource.cs | 6 -- Client/Scripting/ClientScript.cs | 23 ++----- Client/Scripts/EntryPoint.cs | 79 ------------------------- Client/Scripts/Main.cs | 24 ++------ Client/Scripts/Scripting/API.Exports.cs | 27 +++++---- Client/Scripts/Scripting/API.cs | 12 ++-- Client/Scripts/Scripting/Resources.cs | 54 +++-------------- Client/Scripts/Sync/EntityPool.cs | 2 + RageCoop-V.sln | 20 +------ Server/Properties/AssemblyInfo.cs | 4 +- Server/Scripting/API.cs | 2 +- Server/Scripting/Resources.cs | 1 - libs/ScriptHookVDotNetCore | 2 +- 14 files changed, 50 insertions(+), 210 deletions(-) delete mode 100644 Client/Scripts/EntryPoint.cs diff --git a/Client/Scripting/APIBridge.Generated.cs b/Client/Scripting/APIBridge.Generated.cs index fe364d6..ac1de20 100644 --- a/Client/Scripting/APIBridge.Generated.cs +++ b/Client/Scripting/APIBridge.Generated.cs @@ -36,10 +36,12 @@ namespace RageCoop.Client.Scripting public static void LocalChatMessage(System.String from, System.String message) => InvokeCommand("LocalChatMessage", from, message); public static void SendChatMessage(System.String message) => InvokeCommand("SendChatMessage", message); public static RageCoop.Client.Scripting.ClientResource GetResource(System.String name) => InvokeCommand("GetResource", name); - public static RageCoop.Client.Scripting.ClientResource GetResouceFromFilePath(System.String filePath) => InvokeCommand("GetResouceFromFilePath", filePath); + public static RageCoop.Client.Scripting.ClientResource GetResourceFromPath(System.String path) => InvokeCommand("GetResourceFromPath", path); public static System.Object GetConfig(System.String name) => InvokeCommand("GetConfig", name); public static void SetConfig(System.String name, System.String jsonVal) => InvokeCommand("SetConfig", name, jsonVal); public static void RegisterCustomEventHandler(RageCoop.Core.Scripting.CustomEventHash hash, RageCoop.Core.Scripting.CustomEventHandler handler) => InvokeCommand("RegisterCustomEventHandler", hash, handler); + + #endregion } } diff --git a/Client/Scripting/ClientResource.cs b/Client/Scripting/ClientResource.cs index b73adf2..04ae22c 100644 --- a/Client/Scripting/ClientResource.cs +++ b/Client/Scripting/ClientResource.cs @@ -38,12 +38,6 @@ namespace RageCoop.Client.Scripting [JsonProperty] public Dictionary Files { get; internal set; } = new Dictionary(); - /// - /// List of the path of loaded modules, don't modify - /// - [JsonProperty] - public List Modules = new(); - /// /// A instance that can be used to debug your resource. /// diff --git a/Client/Scripting/ClientScript.cs b/Client/Scripting/ClientScript.cs index ceb8ef3..e1ce087 100644 --- a/Client/Scripting/ClientScript.cs +++ b/Client/Scripting/ClientScript.cs @@ -11,29 +11,16 @@ namespace RageCoop.Client.Scripting [ScriptAttributes(NoDefaultInstance = true)] public abstract class ClientScript : Script { - ConcurrentQueue> _jobQueue = new(); - Queue> _reAdd = new(); - /// - /// Fully qualified path to the module that the current script runs in. - /// - public static readonly string FullPath; - static unsafe ClientScript() - { - char* buf = stackalloc char[260]; - // TODO: needs some fix up here - // SHVDN.PInvoke.GetModuleFileNameW(SHVDN.Core.CurrentModule, buf, 260); - if (Marshal.GetLastWin32Error() != 0) - throw new Win32Exception("Failed to get path for current module"); - FullPath = new(buf); - } - + readonly ConcurrentQueue> _jobQueue = new(); + readonly Queue> _reAdd = new(); public ClientScript() { - CurrentResource = APIBridge.GetResouceFromFilePath(FullPath); + var dir = SHVDN.Core.CurrentDirectory; + CurrentResource = APIBridge.GetResourceFromPath(dir); if (CurrentResource == null) throw new Exception("No resource associated with this script is found"); - CurrentFile = CurrentResource.Files.Values.FirstOrDefault(x => x?.FullPath?.ToLower() == FullPath.ToLower()); + CurrentFile = CurrentResource.Files.Values.FirstOrDefault(x => x?.FullPath?.ToLower() == FilePath?.ToLower()); if (CurrentFile == null) { Logger.Warning("No file associated with curent script was found"); diff --git a/Client/Scripts/EntryPoint.cs b/Client/Scripts/EntryPoint.cs deleted file mode 100644 index 2e13573..0000000 --- a/Client/Scripts/EntryPoint.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using GTA; -using RageCoop.Client; -using SHVDN; - -/// -/// Template for generating AOT entrypoints -/// -public static class EntryPoint -{ - private static void ModuleSetup() - { - Script script = new Main(); - Core.RegisterScript(script); - script = new WorldThread(); - Core.RegisterScript(script); - script = new DevTool(); - Core.RegisterScript(script); - } - - [UnmanagedCallersOnly(EntryPoint = "OnInit")] - public unsafe static void OnInit(IntPtr module) - { - try - { - Core.OnInit(module); - ModuleSetup(); - } - catch (Exception ex) - { - PInvoke.MessageBoxA((IntPtr)0, ex.ToString(), "Module initialization error", 0u); - throw; - } - } - - /// - /// Called prior to module unload - /// - /// - [UnmanagedCallersOnly(EntryPoint = "OnUnload")] - public static void OnUnload(IntPtr module) - { - try - { - Core.OnUnload(module); - } - catch (Exception ex) - { - Logger.Error((ReadOnlySpan)("Module unload error: " + ex.ToString())); - } - } - - [UnmanagedCallersOnly(EntryPoint = "OnKeyboard")] - public unsafe static void OnKeyboard(uint key, ushort repeats, bool scanCode, bool isExtended, bool isWithAlt, bool wasDownBefore, bool isUpNow) - { - try - { - Core.DoKeyEvent(key, !isUpNow, (PInvoke.GetAsyncKeyState(17) & 0x8000) != 0, (PInvoke.GetAsyncKeyState(16) & 0x8000) != 0, isWithAlt); - } - catch (Exception ex) - { - Logger.Error((ReadOnlySpan)("Keyboard event error: " + ex.ToString())); - } - } - - [UnmanagedCallersOnly(EntryPoint = "OnTick")] - public static void OnTick(IntPtr currentFiber) - { - try - { - Core.DoTick(currentFiber); - } - catch (Exception ex) - { - Logger.Error((ReadOnlySpan)("Tick error: " + ex.ToString())); - } - } -} \ No newline at end of file diff --git a/Client/Scripts/Main.cs b/Client/Scripts/Main.cs index 62a8ce5..f825d37 100644 --- a/Client/Scripts/Main.cs +++ b/Client/Scripts/Main.cs @@ -35,7 +35,7 @@ namespace RageCoop.Client internal static Logger Log = null; internal static ulong Ticked = 0; internal static Vector3 PlayerPosition; - internal static Scripting.Resources MainRes = null; + internal static Resources MainRes = null; public static Ped P; public static float FPS; @@ -207,22 +207,6 @@ namespace RageCoop.Client protected override void OnKeyUp(GTA.KeyEventArgs e) { base.OnKeyUp(e); - - if (e.KeyCode == Keys.U) - { - foreach (var prop in typeof(APIBridge).GetProperties(BindingFlags.Public | BindingFlags.Static)) - { - Console.PrintInfo($"{prop.Name}: {JsonSerialize(prop.GetValue(null))}"); - } - foreach (var prop in typeof(APIBridge.Config).GetProperties(BindingFlags.Public | BindingFlags.Static)) - { - Console.PrintInfo($"{prop.Name}: {JsonSerialize(prop.GetValue(null))}"); - } - } - if (e.KeyCode == Keys.I) - { - APIBridge.SendChatMessage("test"); - } #if CEF if (CefRunning) { @@ -386,19 +370,19 @@ namespace RageCoop.Client Notification.Show("~r~Disconnected: " + reason); } - if (MainChat?.Focused == true) + if (MainChat.Focused) { MainChat.Focused = false; } PlayerList.Cleanup(); - MainChat?.Clear(); + MainChat.Clear(); EntityPool.Cleanup(); WorldThread.Traffic(true); Call(SET_ENABLE_VEHICLE_SLIPSTREAMING, false); CoopMenu.DisconnectedMenuSetting(); LocalPlayerID = default; - MainRes?.Unload(); + MainRes.Unload(); Memory.RestorePatches(); #if CEF if (CefRunning) diff --git a/Client/Scripts/Scripting/API.Exports.cs b/Client/Scripts/Scripting/API.Exports.cs index ddc8f43..29c84d5 100644 --- a/Client/Scripts/Scripting/API.Exports.cs +++ b/Client/Scripts/Scripting/API.Exports.cs @@ -22,10 +22,10 @@ namespace RageCoop.Client.Scripting { foreach (var method in typeof(API).GetMethods(BindingFlags.Public | BindingFlags.Static)) { - var attri = method.GetCustomAttribute(); + var attri = method.GetCustomAttribute(); if (attri == null) continue; - Debug.Assert(attri.EntryPoint == method.Name); - SHVDN.Core.SetPtr($"{typeof(API).FullName}.{method.Name}", method.MethodHandle.GetFunctionPointer()); + attri.EntryPoint ??= method.Name; + SHVDN.Core.SetPtr($"{typeof(API).FullName}.{attri.EntryPoint}", method.MethodHandle.GetFunctionPointer()); Log.Debug($"Registered function pointer for {method.DeclaringType}.{method.Name}"); } } @@ -33,7 +33,7 @@ namespace RageCoop.Client.Scripting [ThreadStatic] static string _lastResult; - [UnmanagedCallersOnly(EntryPoint = nameof(GetLastResult))] + [ApiExportAttribute(EntryPoint = nameof(GetLastResult))] public static int GetLastResult(char* buf, int cbBufSize) { if (_lastResult == null) @@ -52,7 +52,7 @@ namespace RageCoop.Client.Scripting } public static void SetLastResult(string msg) => _lastResult = msg; - [UnmanagedCallersOnly(EntryPoint = nameof(SetLastResult))] + [ApiExportAttribute(EntryPoint = nameof(SetLastResult))] public static void SetLastResult(char* msg) { try @@ -65,10 +65,10 @@ namespace RageCoop.Client.Scripting } } - [UnmanagedCallersOnly(EntryPoint = nameof(GetEventHash))] + [ApiExportAttribute(EntryPoint = nameof(GetEventHash))] public static CustomEventHash GetEventHash(char* name) => new string(name); - [UnmanagedCallersOnly(EntryPoint = nameof(SendCustomEvent))] + [ApiExportAttribute(EntryPoint = nameof(SendCustomEvent))] public static void SendCustomEvent(CustomEventFlags flags, int hash, byte* data, int cbData) { var payload = new byte[cbData]; @@ -81,7 +81,7 @@ namespace RageCoop.Client.Scripting }, Networking.ServerConnection, ConnectionChannel.Event, NetDeliveryMethod.ReliableOrdered); } - [UnmanagedCallersOnly(EntryPoint = nameof(InvokeCommand))] + [ApiExportAttribute(EntryPoint = nameof(InvokeCommand))] public static int InvokeCommand(char* name, int argc, char** argv) { try @@ -102,13 +102,13 @@ namespace RageCoop.Client.Scripting } } - [UnmanagedCallersOnly(EntryPoint = nameof(GetLastResultLenInChars))] + [ApiExportAttribute(EntryPoint = nameof(GetLastResultLenInChars))] public static int GetLastResultLenInChars() => _lastResult?.Length ?? 0; /// /// Convert Entity ID to handle /// - [UnmanagedCallersOnly(EntryPoint = nameof(IdToHandle))] + [ApiExportAttribute(EntryPoint = nameof(IdToHandle))] public static int IdToHandle(byte type, int id) { return type switch @@ -126,10 +126,15 @@ namespace RageCoop.Client.Scripting /// /// /// - [UnmanagedCallersOnly(EntryPoint = nameof(LogEnqueue))] + [ApiExportAttribute(EntryPoint = nameof(LogEnqueue))] public static void LogEnqueue(LogLevel level, char* msg) { Log.Enqueue((int)level, new(msg)); } + + class ApiExportAttribute : Attribute + { + public string EntryPoint; + } } } diff --git a/Client/Scripts/Scripting/API.cs b/Client/Scripts/Scripting/API.cs index 9fe3e88..84a1dae 100644 --- a/Client/Scripts/Scripting/API.cs +++ b/Client/Scripts/Scripting/API.cs @@ -7,6 +7,7 @@ using RageCoop.Core.Scripting; using SHVDN; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Net; using System.Reflection; @@ -411,16 +412,17 @@ namespace RageCoop.Client.Scripting } /// - /// Get that contains the specified file + /// Get that contains the specified file or directory /// /// [Remoting] - public static ClientResource GetResouceFromFilePath(string filePath) + public static ClientResource GetResourceFromPath(string path) { - foreach (var res in MainRes.LoadedResources) + path = Path.GetFullPath(path).ToLower(); + foreach (var res in MainRes.LoadedResources.Values) { - if (res.Value.Files.Any(file => file.Value.FullPath.ToLower() == filePath.ToLower())) - return res.Value; + if (res.ScriptsDirectory.ToLower() == path || res.Files.Any(file => file.Value.FullPath.ToLower() == path)) + return res; } return null; } diff --git a/Client/Scripts/Scripting/Resources.cs b/Client/Scripts/Scripting/Resources.cs index 3851780..7493cf9 100644 --- a/Client/Scripts/Scripting/Resources.cs +++ b/Client/Scripts/Scripting/Resources.cs @@ -8,18 +8,18 @@ using System.Reflection; using ICSharpCode.SharpZipLib.Zip; using RageCoop.Core; using RageCoop.Core.Scripting; +using SHVDN; namespace RageCoop.Client.Scripting { internal class Resources { - public static string TempPath; + public static string TempPath = Path.Combine(Path.GetTempPath(), "RageCoop"); internal readonly ConcurrentDictionary LoadedResources = new(); static Resources() { - TempPath = Path.Combine(Path.GetTempPath(), "RageCoop"); if (Directory.Exists(TempPath)) try { @@ -47,39 +47,24 @@ namespace RageCoop.Client.Scripting public unsafe void Unload() { - HashSet modules = new(); - foreach (var res in LoadedResources.Values) + var dirs = LoadedResources.Values.Select(x => x.ScriptsDirectory); + foreach (var dir in dirs) { - foreach (var module in res.Modules) - { - fixed (char* pModulePath = module) - { - Log.Debug($"Unloading module: {module}"); - SHVDN.Core.ScheduleUnload(pModulePath); - var hModule = Util.GetModuleHandleW(module); - if (hModule == IntPtr.Zero) - Log.Warning("Failed to get module handler for " + Path.GetFileName(module)); - else - modules.Add(hModule); - } - } + SHVDN.Core.RuntimeController.RequestUnload(dir); } - // TODO - /* // Unregister associated handler foreach (var handlers in API.CustomEventHandlers.Values) { foreach (var handler in handlers.ToArray()) { - if (modules.Contains((IntPtr)handler.Module)) + if (dirs.Contains(handler.Directory, StringComparer.OrdinalIgnoreCase)) { - Log.Debug($"Unregister handler from module {handler.Module}"); handlers.Remove(handler); + Log.Debug($"Unregistered handler from script directory {handler.Directory}"); } } } - */ LoadedResources.Clear(); } @@ -110,21 +95,6 @@ namespace RageCoop.Client.Scripting }); foreach (var file in Directory.GetFiles(scriptsDir, "*", SearchOption.AllDirectories)) { - if (Path.GetFileName(file).CanBeIgnored()) - { - try - { - File.Delete(file); - } - catch (Exception ex) - { - Log.Warning( - $"Failed to delete API assembly: {file}. This may or may cause some unexpected behaviours.\n{ex}"); - } - - continue; - } - var relativeName = file.Substring(scriptsDir.Length + 1).Replace('\\', '/'); var rfile = new ClientFile { @@ -133,16 +103,8 @@ namespace RageCoop.Client.Scripting FullPath = file }; r.Files.Add(relativeName, rfile); - if (file.EndsWith(".dll")) - { - fixed (char* pModulePath = file) - { - SHVDN.Core.ScheduleLoad(pModulePath); - r.Modules.Add(file); - } - } } - + SHVDN.Core.RuntimeController.RequestLoad(scriptsDir); LoadedResources.TryAdd(r.Name, r); return r; } diff --git a/Client/Scripts/Sync/EntityPool.cs b/Client/Scripts/Sync/EntityPool.cs index 20bc0e3..91f4b4b 100644 --- a/Client/Scripts/Sync/EntityPool.cs +++ b/Client/Scripts/Sync/EntityPool.cs @@ -425,6 +425,8 @@ namespace RageCoop.Client if (!VehiclesByHandle.ContainsKey(veh)) { var cveh = (Vehicle)Entity.FromHandle(veh); + if (cveh == null) + continue; if (allVehicles.Length > Settings.WorldVehicleSoftLimit) { var type = cveh.PopulationType; diff --git a/RageCoop-V.sln b/RageCoop-V.sln index 562b9af..a8f6f63 100644 --- a/RageCoop-V.sln +++ b/RageCoop-V.sln @@ -26,15 +26,10 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libs", "libs", "{1AF84C35-B86B-46BB-9FDB-ACB7787E582A}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScriptHookVDotNetCore", "libs\ScriptHookVDotNetCore\src\ScriptHookVDotNetCore\ScriptHookVDotNetCore.csproj", "{B15EDABB-30AF-475A-823D-ACB9F75CFE13}" - ProjectSection(ProjectDependencies) = postProject - {2C08A5AF-C189-4350-B54F-3D23379E9E1D} = {2C08A5AF-C189-4350-B54F-3D23379E9E1D} - EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lidgren.Network", "libs\Lidgren.Network\Lidgren.Network\Lidgren.Network.csproj", "{02616B5A-2A68-42AA-A91E-311EF95FCF44}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScriptHookVDotNetCore.Generator", "libs\ScriptHookVDotNetCore\src\ScriptHookVDotNetCore.Generator\ScriptHookVDotNetCore.Generator.csproj", "{2C08A5AF-C189-4350-B54F-3D23379E9E1D}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeGen", "Tools\CodeGen\CodeGen.csproj", "{C4CF8A98-7393-42BD-97A1-2E850D12890A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodeGen", "Tools\CodeGen\CodeGen.csproj", "{C4CF8A98-7393-42BD-97A1-2E850D12890A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -154,18 +149,6 @@ Global {02616B5A-2A68-42AA-A91E-311EF95FCF44}.Release|Any CPU.Build.0 = Release|Any CPU {02616B5A-2A68-42AA-A91E-311EF95FCF44}.Release|x64.ActiveCfg = Release|Any CPU {02616B5A-2A68-42AA-A91E-311EF95FCF44}.Release|x64.Build.0 = Release|Any CPU - {2C08A5AF-C189-4350-B54F-3D23379E9E1D}.API|Any CPU.ActiveCfg = Debug|Any CPU - {2C08A5AF-C189-4350-B54F-3D23379E9E1D}.API|Any CPU.Build.0 = Debug|Any CPU - {2C08A5AF-C189-4350-B54F-3D23379E9E1D}.API|x64.ActiveCfg = Debug|Any CPU - {2C08A5AF-C189-4350-B54F-3D23379E9E1D}.API|x64.Build.0 = Debug|Any CPU - {2C08A5AF-C189-4350-B54F-3D23379E9E1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2C08A5AF-C189-4350-B54F-3D23379E9E1D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2C08A5AF-C189-4350-B54F-3D23379E9E1D}.Debug|x64.ActiveCfg = Debug|Any CPU - {2C08A5AF-C189-4350-B54F-3D23379E9E1D}.Debug|x64.Build.0 = Debug|Any CPU - {2C08A5AF-C189-4350-B54F-3D23379E9E1D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2C08A5AF-C189-4350-B54F-3D23379E9E1D}.Release|Any CPU.Build.0 = Release|Any CPU - {2C08A5AF-C189-4350-B54F-3D23379E9E1D}.Release|x64.ActiveCfg = Release|Any CPU - {2C08A5AF-C189-4350-B54F-3D23379E9E1D}.Release|x64.Build.0 = Release|Any CPU {C4CF8A98-7393-42BD-97A1-2E850D12890A}.API|Any CPU.ActiveCfg = Debug|Any CPU {C4CF8A98-7393-42BD-97A1-2E850D12890A}.API|Any CPU.Build.0 = Debug|Any CPU {C4CF8A98-7393-42BD-97A1-2E850D12890A}.API|x64.ActiveCfg = Debug|Any CPU @@ -190,7 +173,6 @@ Global {4FE96671-3DC5-4394-B2E3-584399E57310} = {70A1F09D-648D-4C8B-8947-E920B1A587A3} {B15EDABB-30AF-475A-823D-ACB9F75CFE13} = {1AF84C35-B86B-46BB-9FDB-ACB7787E582A} {02616B5A-2A68-42AA-A91E-311EF95FCF44} = {1AF84C35-B86B-46BB-9FDB-ACB7787E582A} - {2C08A5AF-C189-4350-B54F-3D23379E9E1D} = {1AF84C35-B86B-46BB-9FDB-ACB7787E582A} {C4CF8A98-7393-42BD-97A1-2E850D12890A} = {70A1F09D-648D-4C8B-8947-E920B1A587A3} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution diff --git a/Server/Properties/AssemblyInfo.cs b/Server/Properties/AssemblyInfo.cs index 6c4e47c..11a3f05 100644 --- a/Server/Properties/AssemblyInfo.cs +++ b/Server/Properties/AssemblyInfo.cs @@ -15,7 +15,7 @@ using System.Resources; [assembly: AssemblyCulture("")] // Version information -[assembly: AssemblyVersion("1.6.0.45")] -[assembly: AssemblyFileVersion("1.6.0.45")] +[assembly: AssemblyVersion("1.6.0.54")] +[assembly: AssemblyFileVersion("1.6.0.54")] [assembly: NeutralResourcesLanguageAttribute( "en-US" )] diff --git a/Server/Scripting/API.cs b/Server/Scripting/API.cs index 7e09611..4cc9c16 100644 --- a/Server/Scripting/API.cs +++ b/Server/Scripting/API.cs @@ -359,7 +359,7 @@ public class API /// /// An unique identifier of the event/> to get it from a string /// - /// The objects conataing your data, see for + /// The objects conataing your data, see for /// supported types. /// /// The target clients to send. Leave it null to send to all clients diff --git a/Server/Scripting/Resources.cs b/Server/Scripting/Resources.cs index 7ffb90f..b1bd482 100644 --- a/Server/Scripting/Resources.cs +++ b/Server/Scripting/Resources.cs @@ -103,7 +103,6 @@ internal class Resources zip.AddDirectory(dir[(resourceFolder.Length + 1)..]); foreach (var file in Directory.GetFiles(resourceFolder, "*", SearchOption.AllDirectories)) { - if (Path.GetFileName(file).CanBeIgnored()) continue; zip.Add(file, file[(resourceFolder.Length + 1)..]); } diff --git a/libs/ScriptHookVDotNetCore b/libs/ScriptHookVDotNetCore index f531165..f2505ef 160000 --- a/libs/ScriptHookVDotNetCore +++ b/libs/ScriptHookVDotNetCore @@ -1 +1 @@ -Subproject commit f531165cd3d907c6eba75c9ddd3a9928ed612b6c +Subproject commit f2505ef075648520f2bea5fb8b90f45b6a5482b5