Prepare for CoreCLR version
This commit is contained in:
@ -1,9 +1,9 @@
|
|||||||
using RageCoop.Core;
|
using RageCoop.Core;
|
||||||
using RageCoop.Core.Scripting;
|
using RageCoop.Core.Scripting;
|
||||||
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
[assembly: DisableRuntimeMarshalling]
|
|
||||||
[assembly: InternalsVisibleTo("RageCoop.Client")] // For debugging
|
[assembly: InternalsVisibleTo("RageCoop.Client")] // For debugging
|
||||||
|
|
||||||
namespace RageCoop.Client.Scripting
|
namespace RageCoop.Client.Scripting
|
||||||
@ -11,7 +11,28 @@ namespace RageCoop.Client.Scripting
|
|||||||
public static unsafe partial class APIBridge
|
public static unsafe partial class APIBridge
|
||||||
{
|
{
|
||||||
static readonly ThreadLocal<char[]> _resultBuf = new(() => new char[4096]);
|
static readonly ThreadLocal<char[]> _resultBuf = new(() => new char[4096]);
|
||||||
static List<CustomEventHandler> _handlers = new();
|
static readonly List<CustomEventHandler> _handlers = new();
|
||||||
|
|
||||||
|
static APIBridge()
|
||||||
|
{
|
||||||
|
if (SHVDN.Core.GetPtr == null)
|
||||||
|
throw new InvalidOperationException("Game not running");
|
||||||
|
|
||||||
|
foreach(var fd in typeof(APIBridge).GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
|
||||||
|
{
|
||||||
|
var importAttri = fd.GetCustomAttribute<ApiImportAttribute>();
|
||||||
|
if (importAttri == null)
|
||||||
|
continue;
|
||||||
|
importAttri.EntryPoint ??= fd.Name;
|
||||||
|
var key = $"RageCoop.Client.Scripting.API.{importAttri.EntryPoint}";
|
||||||
|
var fptr = SHVDN.Core.GetPtr(key);
|
||||||
|
if (fptr == default)
|
||||||
|
throw new KeyNotFoundException($"Failed to find function pointer: {key}");
|
||||||
|
|
||||||
|
fd.SetValue(null,fptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copy content of string to a sequential block of memory
|
/// Copy content of string to a sequential block of memory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -56,11 +77,14 @@ namespace RageCoop.Client.Scripting
|
|||||||
var argv = StringArrayToMemory(args.Select(JsonSerialize).ToArray());
|
var argv = StringArrayToMemory(args.Select(JsonSerialize).ToArray());
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var resultLen = InvokeCommandAsJsonUnsafe(name, argc, argv);
|
fixed(char* pName = name)
|
||||||
|
{
|
||||||
|
var resultLen = InvokeCommandAsJsonUnsafe(pName, argc, argv);
|
||||||
if (resultLen == 0)
|
if (resultLen == 0)
|
||||||
throw new Exception(GetLastResult());
|
throw new Exception(GetLastResult());
|
||||||
return GetLastResult();
|
return GetLastResult();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
Marshal.FreeHGlobal((IntPtr)argv);
|
Marshal.FreeHGlobal((IntPtr)argv);
|
||||||
@ -77,7 +101,7 @@ namespace RageCoop.Client.Scripting
|
|||||||
var cbBufSize = _resultBuf.Value.Length * sizeof(char);
|
var cbBufSize = _resultBuf.Value.Length * sizeof(char);
|
||||||
fixed (char* pBuf = _resultBuf.Value)
|
fixed (char* pBuf = _resultBuf.Value)
|
||||||
{
|
{
|
||||||
if (GetLastResult(pBuf, cbBufSize) > 0)
|
if (GetLastResultUnsafe(pBuf, cbBufSize) > 0)
|
||||||
{
|
{
|
||||||
return new string(pBuf);
|
return new string(pBuf);
|
||||||
}
|
}
|
||||||
@ -91,7 +115,7 @@ namespace RageCoop.Client.Scripting
|
|||||||
{
|
{
|
||||||
var writer = GetWriter();
|
var writer = GetWriter();
|
||||||
CustomEvents.WriteObjects(writer, args);
|
CustomEvents.WriteObjects(writer, args);
|
||||||
SendCustomEvent(flags, hash, writer.Address, writer.Position);
|
SendCustomEventUnsafe(flags, hash, writer.Address, writer.Position);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RegisterCustomEventHandler(CustomEventHash hash, Action<CustomEventReceivedArgs> handler)
|
public static void RegisterCustomEventHandler(CustomEventHash hash, Action<CustomEventReceivedArgs> handler)
|
||||||
@ -107,25 +131,31 @@ namespace RageCoop.Client.Scripting
|
|||||||
internal static void SetConfig(string name, object val) => InvokeCommand("SetConfig", name, val);
|
internal static void SetConfig(string name, object val) => InvokeCommand("SetConfig", name, val);
|
||||||
|
|
||||||
|
|
||||||
[LibraryImport("RageCoop.Client.dll", StringMarshalling = StringMarshalling.Utf16)]
|
[ApiImport]
|
||||||
public static partial CustomEventHash GetEventHash(string name);
|
public static delegate* unmanaged<char*, CustomEventHash> GetEventHash;
|
||||||
|
|
||||||
[LibraryImport("RageCoop.Client.dll", StringMarshalling = StringMarshalling.Utf16)]
|
[ApiImport]
|
||||||
internal static partial void SetLastResult(string msg);
|
private static delegate* unmanaged<char*,void> SetLastResult;
|
||||||
|
|
||||||
[LibraryImport("RageCoop.Client.dll")]
|
[ApiImport(EntryPoint = "GetLastResult")]
|
||||||
private static partial int GetLastResult(char* buf, int cbBufSize);
|
private static delegate* unmanaged<char*, int, int> GetLastResultUnsafe;
|
||||||
|
|
||||||
[LibraryImport("RageCoop.Client.dll", EntryPoint = "InvokeCommand", StringMarshalling = StringMarshalling.Utf16)]
|
[ApiImport(EntryPoint = "InvokeCommand")]
|
||||||
private static partial int InvokeCommandAsJsonUnsafe(string name, int argc, char** argv);
|
private static delegate* unmanaged<char*, int, char**, int> InvokeCommandAsJsonUnsafe;
|
||||||
|
|
||||||
[LibraryImport("RageCoop.Client.dll")]
|
[ApiImport(EntryPoint = "SendCustomEvent")]
|
||||||
private static partial void SendCustomEvent(CustomEventFlags flags, int hash, byte* data, int cbData);
|
private static delegate* unmanaged<CustomEventFlags, int, byte*, int, void> SendCustomEventUnsafe;
|
||||||
|
|
||||||
[LibraryImport("RageCoop.Client.dll")]
|
[ApiImport]
|
||||||
private static partial int GetLastResultLenInChars();
|
private static delegate* unmanaged<int> GetLastResultLenInChars;
|
||||||
|
|
||||||
[LibraryImport("RageCoop.Client.dll", StringMarshalling = StringMarshalling.Utf16)]
|
[ApiImport]
|
||||||
public static partial void LogEnqueue(LogLevel level, string msg);
|
public static delegate* unmanaged<LogLevel, char*, void> LogEnqueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Field)]
|
||||||
|
class ApiImportAttribute : Attribute
|
||||||
|
{
|
||||||
|
public string EntryPoint;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -20,7 +20,8 @@ namespace RageCoop.Client.Scripting
|
|||||||
static unsafe ClientScript()
|
static unsafe ClientScript()
|
||||||
{
|
{
|
||||||
char* buf = stackalloc char[260];
|
char* buf = stackalloc char[260];
|
||||||
SHVDN.PInvoke.GetModuleFileNameW(SHVDN.Core.CurrentModule, buf, 260);
|
// TODO: needs some fix up here
|
||||||
|
// SHVDN.PInvoke.GetModuleFileNameW(SHVDN.Core.CurrentModule, buf, 260);
|
||||||
if (Marshal.GetLastWin32Error() != 0)
|
if (Marshal.GetLastWin32Error() != 0)
|
||||||
throw new Win32Exception("Failed to get path for current module");
|
throw new Win32Exception("Failed to get path for current module");
|
||||||
FullPath = new(buf);
|
FullPath = new(buf);
|
||||||
@ -37,12 +38,14 @@ namespace RageCoop.Client.Scripting
|
|||||||
{
|
{
|
||||||
Logger.Warning("No file associated with curent script was found");
|
Logger.Warning("No file associated with curent script was found");
|
||||||
}
|
}
|
||||||
|
|
||||||
Tick += DoQueuedJobs;
|
|
||||||
}
|
}
|
||||||
protected void QueueAction(Func<bool> action) => _jobQueue.Enqueue(action);
|
protected void QueueAction(Func<bool> action) => _jobQueue.Enqueue(action);
|
||||||
protected void QueueAction(Action action) => QueueAction(() => { action(); return true; });
|
protected void QueueAction(Action action) => QueueAction(() => { action(); return true; });
|
||||||
|
protected override void OnTick()
|
||||||
|
{
|
||||||
|
base.OnTick();
|
||||||
|
DoQueuedJobs();
|
||||||
|
}
|
||||||
private void DoQueuedJobs()
|
private void DoQueuedJobs()
|
||||||
{
|
{
|
||||||
while (_reAdd.TryDequeue(out var toAdd))
|
while (_reAdd.TryDequeue(out var toAdd))
|
||||||
|
@ -12,13 +12,16 @@ namespace RageCoop.Client.Scripting
|
|||||||
public static readonly ResourceLogger Default = new();
|
public static readonly ResourceLogger Default = new();
|
||||||
public ResourceLogger()
|
public ResourceLogger()
|
||||||
{
|
{
|
||||||
FlushImmediately= true;
|
FlushImmediately = true;
|
||||||
OnFlush += FlushToMainModule;
|
OnFlush += FlushToMainModule;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FlushToMainModule(LogLine line, string fomatted)
|
private unsafe void FlushToMainModule(LogLine line, string fomatted)
|
||||||
{
|
{
|
||||||
APIBridge.LogEnqueue(line.LogLevel, line.Message);
|
fixed (char* pMsg = line.Message)
|
||||||
|
{
|
||||||
|
APIBridge.LogEnqueue(line.LogLevel, pMsg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using GTA.UI;
|
|
||||||
|
|
||||||
namespace RageCoop.Client
|
|
||||||
{
|
|
||||||
internal enum TimeStamp
|
|
||||||
{
|
|
||||||
AddPeds,
|
|
||||||
PedTotal,
|
|
||||||
AddVehicles,
|
|
||||||
VehicleTotal,
|
|
||||||
SendPed,
|
|
||||||
SendPedState,
|
|
||||||
SendVehicle,
|
|
||||||
SendVehicleState,
|
|
||||||
UpdatePed,
|
|
||||||
UpdateVehicle,
|
|
||||||
CheckProjectiles,
|
|
||||||
GetAllEntities,
|
|
||||||
Receive,
|
|
||||||
ProjectilesTotal
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static class Debug
|
|
||||||
{
|
|
||||||
public static Dictionary<TimeStamp, long> TimeStamps = new Dictionary<TimeStamp, long>();
|
|
||||||
private static int _lastNfHandle;
|
|
||||||
|
|
||||||
static Debug()
|
|
||||||
{
|
|
||||||
foreach (TimeStamp t in Enum.GetValues<TimeStamp>()) TimeStamps.Add(t, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string Dump(this Dictionary<TimeStamp, long> d)
|
|
||||||
{
|
|
||||||
var s = "";
|
|
||||||
foreach (var kvp in d) s += kvp.Key + ":" + kvp.Value + "\n";
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void ShowTimeStamps()
|
|
||||||
{
|
|
||||||
Notification.Hide(_lastNfHandle);
|
|
||||||
_lastNfHandle = Notification.Show(TimeStamps.Dump());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,6 +5,7 @@ using System.Diagnostics;
|
|||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using GTA;
|
using GTA;
|
||||||
using GTA.Math;
|
using GTA.Math;
|
||||||
@ -34,7 +35,7 @@ namespace RageCoop.Client
|
|||||||
internal static Logger Log = null;
|
internal static Logger Log = null;
|
||||||
internal static ulong Ticked = 0;
|
internal static ulong Ticked = 0;
|
||||||
internal static Vector3 PlayerPosition;
|
internal static Vector3 PlayerPosition;
|
||||||
internal static Resources MainRes = null;
|
internal static Scripting.Resources MainRes = null;
|
||||||
|
|
||||||
public static Ped P;
|
public static Ped P;
|
||||||
public static float FPS;
|
public static float FPS;
|
||||||
@ -61,7 +62,8 @@ namespace RageCoop.Client
|
|||||||
|
|
||||||
Log = new Logger()
|
Log = new Logger()
|
||||||
{
|
{
|
||||||
Writers = new List<StreamWriter> { CoreUtils.OpenWriter(LogPath) },
|
FlushImmediately = true,
|
||||||
|
Writers = null,
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
LogLevel = 0,
|
LogLevel = 0,
|
||||||
#else
|
#else
|
||||||
@ -70,26 +72,11 @@ namespace RageCoop.Client
|
|||||||
};
|
};
|
||||||
Log.OnFlush += (line, formatted) =>
|
Log.OnFlush += (line, formatted) =>
|
||||||
{
|
{
|
||||||
switch (line.LogLevel)
|
SHVDN.Logger.Write(line.Message, (uint)line.LogLevel);
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
// case LogLevel.Trace:
|
|
||||||
case LogLevel.Debug:
|
|
||||||
Console.PrintInfo(line.Message);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
case LogLevel.Info:
|
|
||||||
Console.PrintInfo(line.Message);
|
|
||||||
break;
|
|
||||||
case LogLevel.Warning:
|
|
||||||
Console.PrintWarning(line.Message);
|
|
||||||
break;
|
|
||||||
case LogLevel.Error:
|
|
||||||
Console.PrintError(line.Message);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Run static constructor to register all function pointers and remoting entries
|
||||||
|
RuntimeHelpers.RunClassConstructor(typeof(API).TypeHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnAborted(AbortedEventArgs e)
|
protected override void OnAborted(AbortedEventArgs e)
|
||||||
@ -120,7 +107,7 @@ namespace RageCoop.Client
|
|||||||
throw new NotSupportedException("Please update your GTA5 to v1.0.1290 or newer!");
|
throw new NotSupportedException("Please update your GTA5 to v1.0.1290 or newer!");
|
||||||
}
|
}
|
||||||
|
|
||||||
MainRes = new Resources();
|
MainRes = new();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -220,6 +207,22 @@ namespace RageCoop.Client
|
|||||||
protected override void OnKeyUp(GTA.KeyEventArgs e)
|
protected override void OnKeyUp(GTA.KeyEventArgs e)
|
||||||
{
|
{
|
||||||
base.OnKeyUp(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 CEF
|
||||||
if (CefRunning)
|
if (CefRunning)
|
||||||
{
|
{
|
||||||
@ -383,19 +386,19 @@ namespace RageCoop.Client
|
|||||||
Notification.Show("~r~Disconnected: " + reason);
|
Notification.Show("~r~Disconnected: " + reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MainChat.Focused)
|
if (MainChat?.Focused == true)
|
||||||
{
|
{
|
||||||
MainChat.Focused = false;
|
MainChat.Focused = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerList.Cleanup();
|
PlayerList.Cleanup();
|
||||||
MainChat.Clear();
|
MainChat?.Clear();
|
||||||
EntityPool.Cleanup();
|
EntityPool.Cleanup();
|
||||||
WorldThread.Traffic(true);
|
WorldThread.Traffic(true);
|
||||||
Call(SET_ENABLE_VEHICLE_SLIPSTREAMING, false);
|
Call(SET_ENABLE_VEHICLE_SLIPSTREAMING, false);
|
||||||
CoopMenu.DisconnectedMenuSetting();
|
CoopMenu.DisconnectedMenuSetting();
|
||||||
LocalPlayerID = default;
|
LocalPlayerID = default;
|
||||||
MainRes.Unload();
|
MainRes?.Unload();
|
||||||
Memory.RestorePatches();
|
Memory.RestorePatches();
|
||||||
#if CEF
|
#if CEF
|
||||||
if (CefRunning)
|
if (CefRunning)
|
||||||
|
@ -38,9 +38,9 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
DiagnosticMenu.Clear();
|
DiagnosticMenu.Clear();
|
||||||
DiagnosticMenu.Add(new NativeItem("EntityPool", EntityPool.DumpDebug()));
|
DiagnosticMenu.Add(new NativeItem("EntityPool", EntityPool.DumpDebug()));
|
||||||
foreach (var pair in Debug.TimeStamps)
|
// foreach (var pair in Debug.TimeStamps)
|
||||||
DiagnosticMenu.Add(
|
// DiagnosticMenu.Add(
|
||||||
new NativeItem(pair.Key.ToString(), pair.Value.ToString(), pair.Value.ToString()));
|
// new NativeItem(pair.Key.ToString(), pair.Value.ToString(), pair.Value.ToString()));
|
||||||
};
|
};
|
||||||
ShowNetworkInfoItem.CheckboxChanged += (s, e) =>
|
ShowNetworkInfoItem.CheckboxChanged += (s, e) =>
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||||
<NoAotCompile>false</NoAotCompile>
|
<NoAotCompile>false</NoAotCompile>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
|
<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
|
||||||
@ -63,9 +64,6 @@
|
|||||||
<PackageReference Include="SharpZipLib" Version="1.4.0" />
|
<PackageReference Include="SharpZipLib" Version="1.4.0" />
|
||||||
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="4.3.0" />
|
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="4.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(SolutionDir)' != '*Undefined*' And '$(NoAotCompile)' != 'true'">
|
|
||||||
<Exec Command="dotnet publish "$(ProjectPath)" -o "$(OutDir)\native" -p:PublishAOT=true -r win-x64 " />
|
|
||||||
</Target>
|
|
||||||
<PropertyGroup Condition="'$(SolutionDir)' != '*Undefined*' AND '$(PublishAot)' != 'true'">
|
<PropertyGroup Condition="'$(SolutionDir)' != '*Undefined*' AND '$(PublishAot)' != 'true'">
|
||||||
<PostBuildEvent Condition=" '$(DevEnvDir)' != '*Undefined*'">
|
<PostBuildEvent Condition=" '$(DevEnvDir)' != '*Undefined*'">
|
||||||
"$(DevEnvDir)TextTransform.exe" -a !!BuildConfiguration!$(Configuration) "$(ProjectDir)Properties\AssemblyInfo.tt"
|
"$(DevEnvDir)TextTransform.exe" -a !!BuildConfiguration!$(Configuration) "$(ProjectDir)Properties\AssemblyInfo.tt"
|
||||||
|
@ -3,6 +3,8 @@ using RageCoop.Core;
|
|||||||
using RageCoop.Core.Scripting;
|
using RageCoop.Core.Scripting;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Reflection;
|
||||||
using System.Reflection.Metadata;
|
using System.Reflection.Metadata;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using static RageCoop.Core.Scripting.CustomEvents;
|
using static RageCoop.Core.Scripting.CustomEvents;
|
||||||
@ -11,6 +13,23 @@ namespace RageCoop.Client.Scripting
|
|||||||
{
|
{
|
||||||
internal static unsafe partial class API
|
internal static unsafe partial class API
|
||||||
{
|
{
|
||||||
|
static API()
|
||||||
|
{
|
||||||
|
RegisterFunctionPointers();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RegisterFunctionPointers()
|
||||||
|
{
|
||||||
|
foreach (var method in typeof(API).GetMethods(BindingFlags.Public | BindingFlags.Static))
|
||||||
|
{
|
||||||
|
var attri = method.GetCustomAttribute<UnmanagedCallersOnlyAttribute>();
|
||||||
|
if (attri == null) continue;
|
||||||
|
Debug.Assert(attri.EntryPoint == method.Name);
|
||||||
|
SHVDN.Core.SetPtr($"{typeof(API).FullName}.{method.Name}", method.MethodHandle.GetFunctionPointer());
|
||||||
|
Log.Debug($"Registered function pointer for {method.DeclaringType}.{method.Name}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[ThreadStatic]
|
[ThreadStatic]
|
||||||
static string _lastResult;
|
static string _lastResult;
|
||||||
|
|
||||||
|
@ -465,8 +465,8 @@ namespace RageCoop.Client.Scripting
|
|||||||
[Remoting]
|
[Remoting]
|
||||||
public static void RegisterCustomEventHandler(CustomEventHash hash, CustomEventHandler handler)
|
public static void RegisterCustomEventHandler(CustomEventHash hash, CustomEventHandler handler)
|
||||||
{
|
{
|
||||||
if (handler.Module == default)
|
if (handler.Directory == default)
|
||||||
throw new ArgumentException("Module not specified");
|
throw new ArgumentException("Script directory not specified");
|
||||||
|
|
||||||
if (handler.FunctionPtr == default)
|
if (handler.FunctionPtr == default)
|
||||||
throw new ArgumentException("Function pointer not specified");
|
throw new ArgumentException("Function pointer not specified");
|
||||||
|
@ -65,6 +65,8 @@ namespace RageCoop.Client.Scripting
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
/*
|
||||||
// Unregister associated handler
|
// Unregister associated handler
|
||||||
foreach (var handlers in API.CustomEventHandlers.Values)
|
foreach (var handlers in API.CustomEventHandlers.Values)
|
||||||
{
|
{
|
||||||
@ -77,7 +79,7 @@ namespace RageCoop.Client.Scripting
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
LoadedResources.Clear();
|
LoadedResources.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,9 +14,13 @@ namespace RageCoop.Client
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal static class ThreadManager
|
internal static class ThreadManager
|
||||||
{
|
{
|
||||||
private static List<Thread> _threads = new();
|
private static readonly List<Thread> _threads = new();
|
||||||
private static Thread _watcher = new(() => _removeStopped());
|
private static readonly Thread _watcher = new(RemoveStopped);
|
||||||
private static void _removeStopped()
|
static ThreadManager()
|
||||||
|
{
|
||||||
|
_watcher.Start();
|
||||||
|
}
|
||||||
|
private static void RemoveStopped()
|
||||||
{
|
{
|
||||||
while (!IsUnloading)
|
while (!IsUnloading)
|
||||||
{
|
{
|
||||||
@ -46,8 +50,10 @@ namespace RageCoop.Client
|
|||||||
{
|
{
|
||||||
Log.Debug($"Thread stopped: " + Environment.CurrentManagedThreadId);
|
Log.Debug($"Thread stopped: " + Environment.CurrentManagedThreadId);
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
created.Name = name;
|
{
|
||||||
|
Name = name
|
||||||
|
};
|
||||||
Log.Debug($"Thread created: {name}, id: {created.ManagedThreadId}");
|
Log.Debug($"Thread created: {name}, id: {created.ManagedThreadId}");
|
||||||
_threads.Add(created);
|
_threads.Add(created);
|
||||||
if (startNow) created.Start();
|
if (startNow) created.Start();
|
||||||
|
@ -50,7 +50,7 @@ namespace RageCoop.Core
|
|||||||
|
|
||||||
internal Logger()
|
internal Logger()
|
||||||
{
|
{
|
||||||
Name = Process.GetCurrentProcess().Id.ToString();
|
Name = Environment.ProcessId.ToString();
|
||||||
if (!FlushImmediately)
|
if (!FlushImmediately)
|
||||||
{
|
{
|
||||||
LoggerThread = new Thread(() =>
|
LoggerThread = new Thread(() =>
|
||||||
@ -164,7 +164,7 @@ namespace RageCoop.Core
|
|||||||
while (_queuedLines.TryDequeue(out var line))
|
while (_queuedLines.TryDequeue(out var line))
|
||||||
{
|
{
|
||||||
var formatted = Format(line);
|
var formatted = Format(line);
|
||||||
Writers.ForEach(x =>
|
Writers?.ForEach(x =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -38,7 +38,7 @@ namespace RageCoop.Core.Scripting
|
|||||||
public CustomEventHandler(IntPtr func) : this()
|
public CustomEventHandler(IntPtr func) : this()
|
||||||
{
|
{
|
||||||
FunctionPtr = (ulong)func;
|
FunctionPtr = (ulong)func;
|
||||||
Module = (ulong)SHVDN.Core.CurrentModule;
|
Directory = SHVDN.Core.CurrentDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
@ -48,7 +48,7 @@ namespace RageCoop.Core.Scripting
|
|||||||
public ulong FunctionPtr { get; private set; }
|
public ulong FunctionPtr { get; private set; }
|
||||||
|
|
||||||
[JsonProperty]
|
[JsonProperty]
|
||||||
public ulong Module { get; private set; }
|
public string Directory { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using GTA.Math;
|
using GTA.Math;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@ -290,7 +291,20 @@ namespace RageCoop.Core.Scripting
|
|||||||
return Args;
|
return Args;
|
||||||
}
|
}
|
||||||
|
|
||||||
[LibraryImport("RageCoop.Client.dll")]
|
static unsafe delegate* unmanaged<byte, int, int> _idToHandlePtr;
|
||||||
public static partial int IdToHandle(byte type, int id);
|
public static unsafe int IdToHandle(byte type, int id)
|
||||||
|
{
|
||||||
|
if (_idToHandlePtr == default)
|
||||||
|
{
|
||||||
|
if (SHVDN.Core.GetPtr == default)
|
||||||
|
throw new InvalidOperationException("Not client");
|
||||||
|
|
||||||
|
_idToHandlePtr = (delegate* unmanaged<byte, int, int>)SHVDN.Core.GetPtr("RageCoop.Client.Scripting.API.IdToHandle");
|
||||||
|
if (_idToHandlePtr == default)
|
||||||
|
throw new KeyNotFoundException("IdToHandle function not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return _idToHandlePtr(type, id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -15,13 +15,13 @@ namespace RageCoop.Core
|
|||||||
{
|
{
|
||||||
static Type JsonTypeCheck(Type type)
|
static Type JsonTypeCheck(Type type)
|
||||||
{
|
{
|
||||||
if (type.GetCustomAttribute<JsonDontSerialize>() != null)
|
if (type?.GetCustomAttribute<JsonDontSerialize>() != null)
|
||||||
throw new TypeAccessException($"The type {type} cannot be serialized");
|
throw new TypeAccessException($"The type {type} cannot be serialized");
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
static object JsonTypeCheck(object obj)
|
static object JsonTypeCheck(object obj)
|
||||||
{
|
{
|
||||||
JsonTypeCheck(obj.GetType());
|
JsonTypeCheck(obj?.GetType());
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
public static readonly JsonSerializerSettings JsonSettings = new();
|
public static readonly JsonSerializerSettings JsonSettings = new();
|
||||||
|
Submodule libs/ScriptHookVDotNetCore updated: fc239b823e...f531165cd3
Reference in New Issue
Block a user