using System; using System.Buffers.Binary; using System.Runtime.InteropServices; namespace SendProxyInterop; public sealed class SendProxyNative : IDisposable { private readonly IntPtr _library; private readonly SetOverrideDelegate _setOverride; private readonly RemoveOverrideDelegate _removeOverride; private readonly ClearOverridesDelegate _clearOverrides; private readonly MarkDirtyDelegate _markDirty; public SendProxyNative(string libraryPath) { _library = NativeLibrary.Load(libraryPath); _setOverride = GetExport("SendProxy_SetOverride"); _removeOverride = GetExport("SendProxy_RemoveOverride"); _clearOverrides = GetExport("SendProxy_ClearOverrides"); _markDirty = GetExport("SendProxy_MarkDirty"); } public int SetBytes(int recipientSlot, int entityIndex, string className, string fieldPath, ReadOnlySpan value) { byte[] bytes = value.ToArray(); return _setOverride(recipientSlot, entityIndex, className, fieldPath, bytes, bytes.Length); } public int SetBool(int recipientSlot, int entityIndex, string className, string fieldPath, bool value) { Span bytes = stackalloc byte[1]; bytes[0] = value ? (byte)1 : (byte)0; return SetBytes(recipientSlot, entityIndex, className, fieldPath, bytes); } public int SetUInt32(int recipientSlot, int entityIndex, string className, string fieldPath, uint value) { Span bytes = stackalloc byte[4]; BinaryPrimitives.WriteUInt32LittleEndian(bytes, value); return SetBytes(recipientSlot, entityIndex, className, fieldPath, bytes); } public int SetInt32(int recipientSlot, int entityIndex, string className, string fieldPath, int value) { Span bytes = stackalloc byte[4]; BinaryPrimitives.WriteInt32LittleEndian(bytes, value); return SetBytes(recipientSlot, entityIndex, className, fieldPath, bytes); } public int SetFloat(int recipientSlot, int entityIndex, string className, string fieldPath, float value) { Span bytes = stackalloc byte[4]; BinaryPrimitives.WriteInt32LittleEndian(bytes, BitConverter.SingleToInt32Bits(value)); return SetBytes(recipientSlot, entityIndex, className, fieldPath, bytes); } public int SetColor(int recipientSlot, int entityIndex, string className, string fieldPath, byte r, byte g, byte b, byte a) { Span bytes = stackalloc byte[] { r, g, b, a }; return SetBytes(recipientSlot, entityIndex, className, fieldPath, bytes); } public bool RemoveOverride(int ruleId) { return _removeOverride(ruleId); } public void ClearOverrides() { _clearOverrides(); } public bool MarkDirty(int entityIndex, string className, string fieldPath) { return _markDirty(entityIndex, className, fieldPath); } public void Dispose() { NativeLibrary.Free(_library); } private T GetExport(string name) where T : Delegate { return Marshal.GetDelegateForFunctionPointer(NativeLibrary.GetExport(_library, name)); } [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)] private delegate int SetOverrideDelegate(int recipientSlot, int entityIndex, string className, string fieldPath, byte[] value, int valueSize); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] [return: MarshalAs(UnmanagedType.I1)] private delegate bool RemoveOverrideDelegate(int ruleId); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate void ClearOverridesDelegate(); [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)] [return: MarshalAs(UnmanagedType.I1)] private delegate bool MarkDirtyDelegate(int entityIndex, string className, string fieldPath); }