using Lidgren.Network; using RageCoop.Core; using RageCoop.Core.Scripting; using System; using System.Collections.Generic; using System.Reflection.Metadata; using System.Runtime.InteropServices; using static RageCoop.Core.Scripting.CustomEvents; namespace RageCoop.Client.Scripting { internal static unsafe partial class API { [ThreadStatic] static string _lastResult; [UnmanagedCallersOnly(EntryPoint = nameof(GetLastResult))] public static int GetLastResult(char* buf, int cbBufSize) { if (_lastResult == null) return 0; fixed (char* pErr = _lastResult) { var cbToCopy = sizeof(char) * (_lastResult.Length + 1); System.Buffer.MemoryCopy(pErr, buf, cbToCopy, Math.Min(cbToCopy, cbBufSize)); if (cbToCopy > cbBufSize && cbBufSize > 0) { buf[cbBufSize / sizeof(char) - 1] = '\0'; // Always add null terminator } return _lastResult.Length; } } public static void SetLastResult(string msg) => _lastResult = msg; [UnmanagedCallersOnly(EntryPoint = nameof(SetLastResult))] public static void SetLastResult(char* msg) { try { SetLastResult(msg == null ? null : new string(msg)); } catch (Exception ex) { SHVDN.PInvoke.MessageBoxA(default, ex.ToString(), "error", default); } } [UnmanagedCallersOnly(EntryPoint = nameof(GetEventHash))] public static CustomEventHash GetEventHash(char* name) => new string(name); [UnmanagedCallersOnly(EntryPoint = nameof(SendCustomEvent))] public static void SendCustomEvent(CustomEventFlags flags, int hash, byte* data, int cbData) { var payload = new byte[cbData]; Marshal.Copy((IntPtr)data, payload, 0, cbData); Networking.Peer.SendTo(new Packets.CustomEvent() { Flags = flags, Payload = payload, Hash = hash }, Networking.ServerConnection, ConnectionChannel.Event, NetDeliveryMethod.ReliableOrdered); } [UnmanagedCallersOnly(EntryPoint = nameof(InvokeCommand))] public static int InvokeCommand(char* name, int argc, char** argv) { try { var args = new string[argc]; for (int i = 0; i < argc; i++) { args[i] = new(argv[i]); } _lastResult = _invokeCommand(new string(name), args); return _lastResult.Length; } catch (Exception ex) { Log.Error(ex); SetLastResult(ex.ToString()); return 0; } } [UnmanagedCallersOnly(EntryPoint = nameof(GetLastResultLenInChars))] public static int GetLastResultLenInChars() => _lastResult?.Length ?? 0; /// /// Convert Entity ID to handle /// [UnmanagedCallersOnly(EntryPoint = nameof(IdToHandle))] public static int IdToHandle(byte type, int id) { return type switch { T_ID_PROP => EntityPool.GetPropByID(id)?.MainProp?.Handle ?? 0, T_ID_PED => EntityPool.GetPedByID(id)?.MainPed?.Handle ?? 0, T_ID_VEH => EntityPool.GetVehicleByID(id)?.MainVehicle?.Handle ?? 0, T_ID_BLIP => EntityPool.GetBlipByID(id)?.Handle ?? 0, _ => 0, }; } /// /// Enqueue a message to the main logger /// /// /// [UnmanagedCallersOnly(EntryPoint = nameof(LogEnqueue))] public static void LogEnqueue(LogLevel level, char* msg) { Log.Enqueue((int)level, new(msg)); } } }