Decompiled source of EyeTracking v1.1.1
Mods/EyeTracking.dll
Decompiled 2 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BlobHandles; using BoneLib; using BoneLib.BoneMenu; using BoneLib.Notifications; using EyeTracking; using EyeTracking.BoneMenu; using EyeTracking.Compatibility; using EyeTracking.Data; using EyeTracking.MarrowSDK; using EyeTracking.Solvers; using EyeTracking.TrackingProviders; using EyeTracking.UserData; using EyeTracking.Utilities; using HarmonyLib; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Fields; using Il2CppSLZ.Marrow; using Il2CppSLZ.VRMK; using Il2CppUltEvents; using MelonLoader; using MelonLoader.Preferences; using Microsoft.CodeAnalysis; using MiniNtp; using OscCore; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using UnityEngine; using UnityEngine.Profiling; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(Core), "EyeTracking", "0.0.1", "Checkerboard", null)] [assembly: MelonGame("Stress Level Zero", "BONELAB")] [assembly: InternalsVisibleTo("OscCore.Tests.Editor")] [assembly: InternalsVisibleTo("OscCore.Tests.Runtime")] [assembly: InternalsVisibleTo("OscCore.Editor")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("EyeTracking")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+46b6d4cf360c427f8675898742c34b77305b76e6")] [assembly: AssemblyProduct("EyeTracking")] [assembly: AssemblyTitle("EyeTracking")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace OscCore { public class OscBlobMessageHandler : MessageHandlerBase { protected byte[] m_Buffer = new byte[128]; public byte[] Buffer => m_Buffer; public int LastReceivedBlobLength { get; private set; } public event Action<byte[], int> OnMessageReceived; public OscBlobMessageHandler(OscReceiver receiver, string address) : base(receiver, address) { } protected override void ValueRead(OscMessageValues values) { LastReceivedBlobLength = values.ReadBlobElement(0, ref m_Buffer); } protected override void InvokeEvent() { this.OnMessageReceived?.Invoke(m_Buffer, LastReceivedBlobLength); } } public class OscBooleanMessageHandler : OscMessageHandler<bool> { public OscBooleanMessageHandler(OscReceiver receiver, string address) : base(receiver, address) { } protected override void ValueRead(OscMessageValues values) { m_Value = values.ReadBooleanElement(0); } } public class OscColorMessageHandler : OscMessageHandler<Color> { public OscColorMessageHandler(OscReceiver receiver, string address) : base(receiver, address) { } protected override void ValueRead(OscMessageValues values) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) m_Value = Color32.op_Implicit(values.ReadColor32Element(0)); } } public class OscFloat64MessageHandler : OscMessageHandler<double> { public OscFloat64MessageHandler(OscReceiver receiver, string address) : base(receiver, address) { } protected override void ValueRead(OscMessageValues values) { m_Value = values.ReadFloat64Element(0); } } public class OscFloatMessageHandler : OscMessageHandler<float> { public OscFloatMessageHandler(OscReceiver receiver, string address) : base(receiver, address) { } protected override void ValueRead(OscMessageValues values) { m_Value = values.ReadFloatElement(0); } } public class OscInt64MessageHandler : OscMessageHandler<long> { public OscInt64MessageHandler(OscReceiver receiver, string address) : base(receiver, address) { } protected override void ValueRead(OscMessageValues values) { m_Value = values.ReadInt64Element(0); } } public class OscIntMessageHandler : OscMessageHandler<int> { public OscIntMessageHandler(OscReceiver receiver, string address) : base(receiver, address) { } protected override void ValueRead(OscMessageValues values) { m_Value = values.ReadIntElement(0); } } public class OscStringMessageHandler : OscMessageHandler<string> { public OscStringMessageHandler(OscReceiver receiver, string address) : base(receiver, address) { } protected override void ValueRead(OscMessageValues values) { m_Value = values.ReadStringElement(0); } } public class OscVector3MessageHandler : OscMessageHandler<Vector3> { public OscVector3MessageHandler(OscReceiver receiver, string address) : base(receiver, address) { } protected override void ValueRead(OscMessageValues values) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) float num = values.ReadFloatElement(0); float num2 = values.ReadFloatElement(1); float num3 = values.ReadFloatElement(2); m_Value = new Vector3(num, num2, num3); } } public abstract class MessageHandlerBase : IDisposable { protected OscReceiver m_Receiver; protected string m_Address = "/"; protected OscActionPair m_ActionPair; protected bool m_Registered; protected bool m_Disposed; public OscReceiver Receiver => m_Receiver; public string Address => m_Address; public MessageHandlerBase(OscReceiver receiver, string address) { m_Receiver = receiver; m_Address = address; Initialize(); } protected virtual void Initialize() { if (!m_Registered && !string.IsNullOrEmpty(Address) && m_Receiver?.Server != null) { m_ActionPair = new OscActionPair(ValueRead, InvokeEvent); Receiver.Server.TryAddMethodPair(Address, m_ActionPair); m_Registered = true; } } public virtual void Dispose() { if (!m_Disposed) { m_Registered = false; m_Receiver?.Server?.RemoveMethodPair(Address, m_ActionPair); m_Disposed = true; } } protected abstract void InvokeEvent(); protected abstract void ValueRead(OscMessageValues values); } public abstract class OscMessageHandler<T> : MessageHandlerBase { protected T m_Value; public event Action<T> OnMessageReceived; public OscMessageHandler(OscReceiver receiver, string address) : base(receiver, address) { } protected override void InvokeEvent() { this.OnMessageReceived?.Invoke(m_Value); } } public class OscReceiver : IDisposable { private int m_Port = 9000; private bool m_Disposed; public int Port { get { return m_Port; } set { SetPort(value); } } public bool Running { get; private set; } public OscServer Server { get; private set; } public OscReceiver(int port = 9000) { m_Port = port.ClampPort(); Initialize(); } private void Initialize() { Server = OscServer.GetOrCreate(m_Port); Running = true; } public void Update() { Server?.Update(); } public void Dispose() { if (!m_Disposed) { Server?.Dispose(); Server = null; Running = false; m_Disposed = true; } } private void SetPort(int newPort) { if (newPort.ClampPort() != newPort) { return; } int port = m_Port; OscServer server = Server; try { Server = OscServer.GetOrCreate(newPort); m_Port = newPort; server?.Dispose(); } catch { m_Port = port; Server = server; } } } public class OscSender : IDisposable { private string m_IpAddress = "127.0.0.1"; private int m_Port = 7000; private bool m_Disposed; public string IpAddress { get { return m_IpAddress; } set { if (IPAddress.TryParse(value, out IPAddress _)) { m_IpAddress = value; ReInitialize(); } } } public int Port { get { return m_Port; } set { m_Port = value.ClampPort(); ReInitialize(); } } public OscClient Client { get; private set; } public OscSender(int port = 7000, string ipAddress = "127.0.0.1") { m_IpAddress = ipAddress; m_Port = port.ClampPort(); Setup(); } private void Setup() { if (Client == null) { Client = new OscClient(m_IpAddress, m_Port); } } private void ReInitialize() { if (!m_Disposed) { Client = null; Setup(); } } public void Dispose() { if (!m_Disposed) { Client = null; m_Disposed = true; } } } internal static class Constant { public const byte Comma = 44; public const byte ForwardSlash = 47; public static readonly byte[] BundlePrefixBytes; public static readonly long BundlePrefixLong; static Constant() { byte[] bytes = Encoding.ASCII.GetBytes("#bundle "); bytes[7] = 0; BundlePrefixBytes = bytes; BundlePrefixLong = BitConverter.ToInt64(bytes, 0); } } public delegate void MonitorCallback(BlobString address, OscMessageValues values); internal enum AddressType { Invalid, Pattern, Address } public enum TypeTag : byte { False = 70, Infinitum = 73, Nil = 78, AltTypeString = 83, True = 84, ArrayStart = 91, ArrayEnd = 93, Blob = 98, AsciiChar32 = 99, Float64 = 100, Float32 = 102, Int64 = 104, Int32 = 105, MIDI = 109, Color32 = 114, String = 115, TimeTag = 116 } public static class TypeTagMethods { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsSupported(this TypeTag tag) { switch (tag) { case TypeTag.False: case TypeTag.Infinitum: case TypeTag.Nil: case TypeTag.AltTypeString: case TypeTag.True: case TypeTag.ArrayStart: case TypeTag.ArrayEnd: case TypeTag.Blob: case TypeTag.AsciiChar32: case TypeTag.Float64: case TypeTag.Float32: case TypeTag.Int64: case TypeTag.Int32: case TypeTag.MIDI: case TypeTag.Color32: case TypeTag.String: case TypeTag.TimeTag: return true; default: return false; } } } internal enum Vector3ElementFilter : byte { XYZ, X, Y, Z, XY, XZ, YZ } internal enum Vector2ElementFilter : byte { XY, X, Y } public sealed class OscMessageValues { private const int k_ResizeByteHeadroom = 1024; private readonly byte[] m_SharedBuffer; private unsafe readonly byte* SharedBufferPtr; private readonly byte[] m_SwapBuffer32 = new byte[4]; private unsafe readonly float* SwapBuffer32Ptr; private unsafe readonly uint* SwapBuffer32UintPtr; private unsafe readonly Color32* SwapBufferColor32Ptr; private readonly GCHandle m_Swap32Handle; private readonly byte[] m_SwapBuffer64 = new byte[8]; private unsafe readonly double* SwapBuffer64Ptr; private readonly GCHandle m_Swap64Handle; internal readonly TypeTag[] Tags; internal readonly int[] Offsets; public int ElementCount { get; internal set; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public char ReadAsciiCharElement(int index) { if (Tags[index] == TypeTag.AsciiChar32) { return (char)m_SharedBuffer[Offsets[index] + 3]; } return '\0'; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public int ReadBlobElement(int index, ref byte[] copyTo, int copyOffset = 0) { if (Tags[index] == TypeTag.Blob) { int num = Offsets[index]; int num2 = ReadIntIndex(num); int srcOffset = num + 4; if (copyTo.Length - copyOffset <= num2) { Array.Resize(ref copyTo, num2 + copyOffset + 1024); } Buffer.BlockCopy(m_SharedBuffer, srcOffset, copyTo, copyOffset, num2); return num2; } return 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool ReadBooleanElement(int index) { return Tags[index] switch { TypeTag.True => true, TypeTag.False => false, TypeTag.Int32 => ReadIntElementUnchecked(index) > 0, _ => false, }; } public unsafe Color32 ReadColor32Element(int index) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) int num = Offsets[index]; if (Tags[index] == TypeTag.Color32) { m_SwapBuffer32[0] = m_SharedBuffer[num + 3]; m_SwapBuffer32[1] = m_SharedBuffer[num + 2]; m_SwapBuffer32[2] = m_SharedBuffer[num + 1]; m_SwapBuffer32[3] = m_SharedBuffer[num]; return *SwapBufferColor32Ptr; } return default(Color32); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe Color32 ReadColor32ElementUnchecked(int index) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) int num = Offsets[index]; m_SwapBuffer32[0] = m_SharedBuffer[num + 3]; m_SwapBuffer32[1] = m_SharedBuffer[num + 2]; m_SwapBuffer32[2] = m_SharedBuffer[num + 1]; m_SwapBuffer32[3] = m_SharedBuffer[num]; return *SwapBufferColor32Ptr; } internal unsafe OscMessageValues(byte[] buffer, int elementCapacity = 8) { ElementCount = 0; Tags = new TypeTag[elementCapacity]; Offsets = new int[elementCapacity]; m_SharedBuffer = buffer; fixed (byte* sharedBufferPtr = buffer) { SharedBufferPtr = sharedBufferPtr; } m_Swap32Handle = GCHandle.Alloc(m_SwapBuffer32, GCHandleType.Pinned); IntPtr intPtr = m_Swap32Handle.AddrOfPinnedObject(); SwapBuffer32Ptr = (float*)(void*)intPtr; SwapBuffer32UintPtr = (uint*)(void*)intPtr; SwapBufferColor32Ptr = (Color32*)(void*)intPtr; SwapBuffer64Ptr = Utils.PinPtr<byte, double>(m_SwapBuffer64, out m_Swap64Handle); } ~OscMessageValues() { m_Swap32Handle.Free(); m_Swap64Handle.Free(); } public void ForEachElement(Action<int, TypeTag> elementAction) { for (int i = 0; i < ElementCount; i++) { elementAction(i, Tags[i]); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private bool OutOfBounds(int index) { if (index >= ElementCount) { ((MelonBase)Core.Instance).LoggerInstance.Error($"Tried to read message element index {index}, but there are only {ElementCount} elements"); return true; } return false; } public unsafe float ReadFloatElement(int index) { int num = Offsets[index]; switch (Tags[index]) { case TypeTag.Float32: m_SwapBuffer32[0] = SharedBufferPtr[num + 3]; m_SwapBuffer32[1] = SharedBufferPtr[num + 2]; m_SwapBuffer32[2] = SharedBufferPtr[num + 1]; m_SwapBuffer32[3] = SharedBufferPtr[num]; return *SwapBuffer32Ptr; case TypeTag.Int32: return (SharedBufferPtr[index] << 24) | (SharedBufferPtr[index + 1] << 16) | (SharedBufferPtr[index + 2] << 8) | SharedBufferPtr[index + 3]; default: return 0f; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe float ReadFloatElementUnchecked(int index) { int num = Offsets[index]; m_SwapBuffer32[0] = SharedBufferPtr[num + 3]; m_SwapBuffer32[1] = SharedBufferPtr[num + 2]; m_SwapBuffer32[2] = SharedBufferPtr[num + 1]; m_SwapBuffer32[3] = SharedBufferPtr[num]; return *SwapBuffer32Ptr; } public unsafe double ReadFloat64Element(int index) { int num = Offsets[index]; switch (Tags[index]) { case TypeTag.Float64: m_SwapBuffer64[7] = m_SharedBuffer[num]; m_SwapBuffer64[6] = m_SharedBuffer[num + 1]; m_SwapBuffer64[5] = m_SharedBuffer[num + 2]; m_SwapBuffer64[4] = m_SharedBuffer[num + 3]; m_SwapBuffer64[3] = m_SharedBuffer[num + 4]; m_SwapBuffer64[2] = m_SharedBuffer[num + 5]; m_SwapBuffer64[1] = m_SharedBuffer[num + 6]; m_SwapBuffer64[0] = m_SharedBuffer[num + 7]; return *SwapBuffer64Ptr; case TypeTag.Float32: m_SwapBuffer32[0] = m_SharedBuffer[num + 3]; m_SwapBuffer32[1] = m_SharedBuffer[num + 2]; m_SwapBuffer32[2] = m_SharedBuffer[num + 1]; m_SwapBuffer32[3] = m_SharedBuffer[num]; return *SwapBuffer32Ptr; case TypeTag.Int64: return IPAddress.NetworkToHostOrder((long)SharedBufferPtr[num]); case TypeTag.Int32: return (m_SharedBuffer[index] << 24) | (m_SharedBuffer[index + 1] << 16) | (m_SharedBuffer[index + 2] << 8) | m_SharedBuffer[index + 3]; default: return 0.0; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe double ReadFloat64ElementUnchecked(int index) { int num = Offsets[index]; m_SwapBuffer64[7] = m_SharedBuffer[num]; m_SwapBuffer64[6] = m_SharedBuffer[num + 1]; m_SwapBuffer64[5] = m_SharedBuffer[num + 2]; m_SwapBuffer64[4] = m_SharedBuffer[num + 3]; m_SwapBuffer64[3] = m_SharedBuffer[num + 4]; m_SwapBuffer64[2] = m_SharedBuffer[num + 5]; m_SwapBuffer64[1] = m_SharedBuffer[num + 6]; m_SwapBuffer64[0] = m_SharedBuffer[num + 7]; return *SwapBuffer64Ptr; } public unsafe int ReadIntElement(int index) { int num = Offsets[index]; switch (Tags[index]) { case TypeTag.Int32: return (m_SharedBuffer[num] << 24) | (m_SharedBuffer[num + 1] << 16) | (m_SharedBuffer[num + 2] << 8) | m_SharedBuffer[num + 3]; case TypeTag.Float32: m_SwapBuffer32[0] = m_SharedBuffer[num + 3]; m_SwapBuffer32[1] = m_SharedBuffer[num + 2]; m_SwapBuffer32[2] = m_SharedBuffer[num + 1]; m_SwapBuffer32[3] = m_SharedBuffer[num]; return (int)(*SwapBuffer32Ptr); default: return 0; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public int ReadIntElementUnchecked(int index) { int num = Offsets[index]; return (m_SharedBuffer[num] << 24) | (m_SharedBuffer[num + 1] << 16) | (m_SharedBuffer[num + 2] << 8) | m_SharedBuffer[num + 3]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal unsafe uint ReadUIntIndex(int index) { m_SwapBuffer32[0] = m_SharedBuffer[index + 3]; m_SwapBuffer32[1] = m_SharedBuffer[index + 2]; m_SwapBuffer32[2] = m_SharedBuffer[index + 1]; m_SwapBuffer32[3] = m_SharedBuffer[index]; return *SwapBuffer32UintPtr; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal int ReadIntIndex(int index) { return (m_SharedBuffer[index] << 24) | (m_SharedBuffer[index + 1] << 16) | (m_SharedBuffer[index + 2] << 8) | m_SharedBuffer[index + 3]; } public unsafe long ReadInt64Element(int index) { int num = Offsets[index]; switch (Tags[index]) { case TypeTag.Int64: return IPAddress.NetworkToHostOrder((long)SharedBufferPtr[num]); case TypeTag.Int32: return (m_SharedBuffer[num] << 24) | (m_SharedBuffer[num + 1] << 16) | (m_SharedBuffer[num + 2] << 8) | m_SharedBuffer[num + 3]; case TypeTag.Float64: m_SwapBuffer64[7] = m_SharedBuffer[num]; m_SwapBuffer64[6] = m_SharedBuffer[num + 1]; m_SwapBuffer64[5] = m_SharedBuffer[num + 2]; m_SwapBuffer64[4] = m_SharedBuffer[num + 3]; m_SwapBuffer64[3] = m_SharedBuffer[num + 4]; m_SwapBuffer64[2] = m_SharedBuffer[num + 5]; m_SwapBuffer64[1] = m_SharedBuffer[num + 6]; m_SwapBuffer64[0] = m_SharedBuffer[num + 7]; return (long)(*SwapBuffer64Ptr); case TypeTag.Float32: m_SwapBuffer32[0] = m_SharedBuffer[num + 3]; m_SwapBuffer32[1] = m_SharedBuffer[num + 2]; m_SwapBuffer32[2] = m_SharedBuffer[num + 1]; m_SwapBuffer32[3] = m_SharedBuffer[num]; return (long)(*SwapBuffer32Ptr); default: return 0L; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe long ReadInt64ElementUnchecked(int index) { return IPAddress.NetworkToHostOrder((long)SharedBufferPtr[Offsets[index]]); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe MidiMessage ReadMidiElement(int index) { if (Tags[index] == TypeTag.MIDI) { return *(MidiMessage*)(SharedBufferPtr + Offsets[index]); } return default(MidiMessage); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe MidiMessage ReadMidiElementUnchecked(int index) { return *(MidiMessage*)(SharedBufferPtr + Offsets[index]); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool ReadNilOrInfinitumElement(int index) { TypeTag typeTag = Tags[index]; if (typeTag == TypeTag.Infinitum || typeTag == TypeTag.Nil) { return true; } return false; } public unsafe string ReadStringElement(int index) { //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) int num = Offsets[index]; switch (Tags[index]) { case TypeTag.AltTypeString: case TypeTag.String: { int i; for (i = 0; m_SharedBuffer[num + i] != 0; i++) { } return Encoding.UTF8.GetString(m_SharedBuffer, num, i); } case TypeTag.Float64: { m_SwapBuffer64[7] = m_SharedBuffer[num]; m_SwapBuffer64[6] = m_SharedBuffer[num + 1]; m_SwapBuffer64[5] = m_SharedBuffer[num + 2]; m_SwapBuffer64[4] = m_SharedBuffer[num + 3]; m_SwapBuffer64[3] = m_SharedBuffer[num + 4]; m_SwapBuffer64[2] = m_SharedBuffer[num + 5]; m_SwapBuffer64[1] = m_SharedBuffer[num + 6]; m_SwapBuffer64[0] = m_SharedBuffer[num + 7]; double swapBuffer64Ptr = *SwapBuffer64Ptr; return swapBuffer64Ptr.ToString(CultureInfo.CurrentCulture); } case TypeTag.Float32: { m_SwapBuffer32[0] = m_SharedBuffer[num + 3]; m_SwapBuffer32[1] = m_SharedBuffer[num + 2]; m_SwapBuffer32[2] = m_SharedBuffer[num + 1]; m_SwapBuffer32[3] = m_SharedBuffer[num]; float swapBuffer32Ptr = *SwapBuffer32Ptr; return swapBuffer32Ptr.ToString(CultureInfo.CurrentCulture); } case TypeTag.Int64: return IPAddress.NetworkToHostOrder(m_SharedBuffer[num]).ToString(CultureInfo.CurrentCulture); case TypeTag.Int32: return ((m_SharedBuffer[num] << 24) | (m_SharedBuffer[num + 1] << 16) | (m_SharedBuffer[num + 2] << 8) | m_SharedBuffer[num + 3]).ToString(CultureInfo.CurrentCulture); case TypeTag.False: return "False"; case TypeTag.True: return "True"; case TypeTag.Nil: return "Nil"; case TypeTag.Infinitum: return "Infinitum"; case TypeTag.Color32: { m_SwapBuffer32[0] = m_SharedBuffer[num + 3]; m_SwapBuffer32[1] = m_SharedBuffer[num + 2]; m_SwapBuffer32[2] = m_SharedBuffer[num + 1]; m_SwapBuffer32[3] = m_SharedBuffer[num]; Color32 swapBufferColor32Ptr = *SwapBufferColor32Ptr; return ((object)(Color32)(ref swapBufferColor32Ptr)).ToString(); } case TypeTag.MIDI: { MidiMessage midiMessage = *(MidiMessage*)(SharedBufferPtr + num); return midiMessage.ToString(); } case TypeTag.AsciiChar32: { char c = (char)m_SharedBuffer[num + 3]; return c.ToString(); } default: return string.Empty; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public int ReadStringElementBytes(int index, byte[] copyTo) { TypeTag typeTag = Tags[index]; if (typeTag == TypeTag.AltTypeString || typeTag == TypeTag.String) { int num = Offsets[index]; int i; for (i = num; i < m_SharedBuffer.Length; i++) { byte b = m_SharedBuffer[i]; if (b == 0) { break; } copyTo[i - num] = b; } return i - num; } return 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public int ReadStringElementBytes(int index, byte[] copyTo, int copyOffset) { TypeTag typeTag = Tags[index]; if (typeTag == TypeTag.AltTypeString || typeTag == TypeTag.String) { int num = Offsets[index]; int num2 = num - copyOffset; int i; for (i = num; i < m_SharedBuffer.Length; i++) { byte b = m_SharedBuffer[i]; if (b == 0) { break; } copyTo[i - num2] = b; } return i - num; } return 0; } public unsafe NtpTimestamp ReadTimestampElement(int index) { if (Tags[index] == TypeTag.TimeTag) { return NtpTimestamp.FromBigEndianBytes(SharedBufferPtr + Offsets[index]); } return default(NtpTimestamp); } public unsafe NtpTimestamp ReadTimestampElementUnchecked(int index) { return NtpTimestamp.FromBigEndianBytes(SharedBufferPtr + Offsets[index]); } internal unsafe NtpTimestamp ReadTimestampIndex(int index) { byte* num = SharedBufferPtr + index; uint num2 = *(uint*)num; uint seconds = ((num2 & 0xFF) << 24) | ((num2 & 0xFF00) << 8) | ((num2 & 0xFF0000) >> 8) | ((num2 & 0xFF000000u) >> 24); uint num3 = *(uint*)(num + 4); uint fractions = ((num3 & 0xFF) << 24) | ((num3 & 0xFF00) << 8) | ((num3 & 0xFF0000) >> 8) | ((num3 & 0xFF000000u) >> 24); return new NtpTimestamp(seconds, fractions); } } public class OscActionPair { public readonly Action<OscMessageValues> ValueRead; public readonly Action MainThreadQueued; public OscActionPair(Action<OscMessageValues> valueRead, Action mainThreadQueued = null) { ValueRead = valueRead ?? throw new ArgumentNullException("valueRead", "Value read callbacks required!"); MainThreadQueued = mainThreadQueued; } public static OscActionPair operator +(OscActionPair l, OscActionPair r) { Action mainThreadQueued = ((l.MainThreadQueued == null) ? r.MainThreadQueued : ((Action)Delegate.Combine(l.MainThreadQueued, r.MainThreadQueued))); return new OscActionPair((Action<OscMessageValues>)Delegate.Combine(l.ValueRead, r.ValueRead), mainThreadQueued); } public static OscActionPair operator -(OscActionPair l, OscActionPair r) { Action mainThreadQueued = ((l.MainThreadQueued == null) ? r.MainThreadQueued : ((Action)Delegate.Remove(l.MainThreadQueued, r.MainThreadQueued))); return new OscActionPair((Action<OscMessageValues>)Delegate.Remove(l.ValueRead, r.ValueRead), mainThreadQueued); } } public sealed class OscAddressSpace { private const int k_DefaultPatternCapacity = 8; private const int k_DefaultCapacity = 16; private StringBuilder escapedStringBuilder = new StringBuilder(); private HashSet<char> specialRegexCharacters = new HashSet<char>(new char[14] { '.', '^', '$', '*', '+', '?', '{', '}', '[', ']', '\\', '|', '(', ')' }); internal readonly OscAddressMethods AddressToMethod; internal int PatternCount; internal Regex[] Patterns = new Regex[8]; internal OscActionPair[] PatternMethods = new OscActionPair[8]; private readonly Queue<int> FreedPatternIndices = new Queue<int>(); private readonly Dictionary<string, int> PatternStringToIndex = new Dictionary<string, int>(); public int HandlerCount => AddressToMethod.HandleToValue.Count; public IEnumerable<string> Addresses => AddressToMethod.SourceToBlob.Keys; public OscAddressSpace(int startingCapacity = 16) { AddressToMethod = new OscAddressMethods(startingCapacity); } public bool TryAddMethod(string address, OscActionPair onReceived) { if (string.IsNullOrEmpty(address) || onReceived == null) { return false; } switch (OscParser.GetAddressType(address)) { case AddressType.Address: AddressToMethod.Add(address, onReceived); return true; case AddressType.Pattern: { if (PatternStringToIndex.TryGetValue(address, out var value)) { OscActionPair[] patternMethods = PatternMethods; int num = value; patternMethods[num] += onReceived; return true; } if (FreedPatternIndices.Count > 0) { value = FreedPatternIndices.Dequeue(); } else { value = PatternCount; if (value >= Patterns.Length) { int newSize = Patterns.Length * 2; Array.Resize(ref Patterns, newSize); Array.Resize(ref PatternMethods, newSize); } } Regex regex = null; try { regex = new Regex(address); } catch (ArgumentException ex) { try { regex = new Regex(EscapeRegexSpecialCharacters(address)); } catch (Exception) { throw ex; } } Patterns[value] = regex; PatternMethods[value] = onReceived; PatternStringToIndex[address] = value; PatternCount++; return true; } default: return false; } } public bool RemoveAddressMethod(string address) { if (string.IsNullOrEmpty(address)) { return false; } if (OscParser.GetAddressType(address) == AddressType.Address) { return AddressToMethod.RemoveAddress(address); } return false; } public bool RemoveMethod(string address, OscActionPair onReceived) { if (string.IsNullOrEmpty(address) || onReceived == null) { return false; } switch (OscParser.GetAddressType(address)) { case AddressType.Address: return AddressToMethod.Remove(address, onReceived); case AddressType.Pattern: { if (!PatternStringToIndex.TryGetValue(address, out var value)) { return false; } if (PatternMethods[value].ValueRead.GetInvocationList().Length == 1) { Patterns[value] = null; PatternMethods[value] = null; } else { OscActionPair[] patternMethods = PatternMethods; int num = value; patternMethods[num] -= onReceived; } PatternCount--; FreedPatternIndices.Enqueue(value); return PatternStringToIndex.Remove(address); } default: return false; } } public bool TryMatchPatternHandler(string address, List<OscActionPair> allMatchedMethods) { if (!OscParser.AddressIsValid(address)) { return false; } allMatchedMethods.Clear(); bool result = false; for (int i = 0; i < PatternCount; i++) { if (Patterns[i].IsMatch(address)) { OscActionPair callbacks = PatternMethods[i]; AddressToMethod.Add(address, callbacks); result = true; } } return result; } private string EscapeRegexSpecialCharacters(string input) { if (string.IsNullOrEmpty(input)) { return input; } escapedStringBuilder.Clear(); foreach (char c in input) { if (specialRegexCharacters.Contains(c)) { escapedStringBuilder.Append('\\'); } escapedStringBuilder.Append(c); } return escapedStringBuilder.ToString(); } } public class OscClient { protected readonly Socket m_Socket; protected readonly OscWriter m_Writer; private const uint k_Int32TypeTagBytes = 26924u; private const uint k_Float32TypeTagBytes = 26156u; private const uint k_StringTypeTagBytes = 29484u; private const uint k_BlobTypeTagBytes = 25132u; private const uint k_Int64TypeTagBytes = 25644u; private const uint k_Float64TypeTagBytes = 26668u; private const uint k_Color32TypeTagBytes = 29228u; private const uint k_MidiTypeTagBytes = 27948u; private const uint k_CharTypeTagBytes = 25388u; private const uint k_TrueTypeTagBytes = 21548u; private const uint k_FalseTypeTagBytes = 17964u; private const uint k_NilTypeTagBytes = 20012u; private const uint k_InfinitumTypeTagBytes = 18732u; public OscWriter Writer => m_Writer; public IPEndPoint Destination { get; } public OscClient(string ipAddress, int port) { m_Writer = new OscWriter(); m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); if (ipAddress == "255.255.255.255") { m_Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, optionValue: true); } Destination = new IPEndPoint(IPAddress.Parse(ipAddress), port); m_Socket.Connect(Destination); } public void Send(string address) { m_Writer.Reset(); m_Writer.Write(address); m_Writer.Write(","); m_Socket.Send(m_Writer.Buffer, m_Writer.Length, SocketFlags.None); } public void Send(string address, int element) { m_Writer.WriteAddressAndTags(address, 26924u); m_Writer.Write(element); m_Socket.Send(m_Writer.Buffer, m_Writer.Length, SocketFlags.None); } public void Send(string address, float element) { m_Writer.WriteAddressAndTags(address, 26156u); m_Writer.Write(element); m_Socket.Send(m_Writer.Buffer, m_Writer.Length, SocketFlags.None); } public void Send(string address, string element) { m_Writer.WriteAddressAndTags(address, 29484u); m_Writer.Write(element); m_Socket.Send(m_Writer.Buffer, m_Writer.Length, SocketFlags.None); } public void Send(string address, byte[] bytes, int length, int start = 0) { m_Writer.WriteAddressAndTags(address, 25132u); m_Writer.Write(bytes, length, start); m_Socket.Send(m_Writer.Buffer, m_Writer.Length, SocketFlags.None); } public void Send(string address, Vector2 element) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) m_Writer.Reset(); m_Writer.Write(address); m_Writer.Write(",ff"); m_Writer.Write(element); m_Socket.Send(m_Writer.Buffer, m_Writer.Length, SocketFlags.None); } public void Send(string address, float element1, float element2) { m_Writer.Reset(); m_Writer.Write(address); m_Writer.Write(",ff"); m_Writer.Write(element1); m_Writer.Write(element2); m_Socket.Send(m_Writer.Buffer, m_Writer.Length, SocketFlags.None); } public void Send(string address, Vector3 element) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) m_Writer.Reset(); m_Writer.Write(address); m_Writer.Write(",fff"); m_Writer.Write(element); m_Socket.Send(m_Writer.Buffer, m_Writer.Length, SocketFlags.None); } public void Send(string address, float element1, float element2, float element3) { m_Writer.Reset(); m_Writer.Write(address); m_Writer.Write(",fff"); m_Writer.Write(element1); m_Writer.Write(element2); m_Writer.Write(element3); m_Socket.Send(m_Writer.Buffer, m_Writer.Length, SocketFlags.None); } public void Send(string address, float element1, float element2, float element3, float element4) { m_Writer.Reset(); m_Writer.Write(address); m_Writer.Write(",ffff"); m_Writer.Write(element1); m_Writer.Write(element2); m_Writer.Write(element3); m_Writer.Write(element4); m_Socket.Send(m_Writer.Buffer, m_Writer.Length, SocketFlags.None); } public void Send(string address, Vector3 element1, Vector3 element2) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) m_Writer.Reset(); m_Writer.Write(address); m_Writer.Write(",ffffff"); m_Writer.Write(element1); m_Writer.Write(element2); m_Socket.Send(m_Writer.Buffer, m_Writer.Length, SocketFlags.None); } public void Send(string address, double element) { m_Writer.WriteAddressAndTags(address, 25644u); m_Writer.Write(element); m_Socket.Send(m_Writer.Buffer, m_Writer.Length, SocketFlags.None); } public void Send(string address, long element) { m_Writer.WriteAddressAndTags(address, 26668u); m_Writer.Write(element); m_Socket.Send(m_Writer.Buffer, m_Writer.Length, SocketFlags.None); } public void Send(string address, Color32 element) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) m_Writer.WriteAddressAndTags(address, 29228u); m_Writer.Write(element); m_Socket.Send(m_Writer.Buffer, m_Writer.Length, SocketFlags.None); } public void Send(string address, MidiMessage element) { m_Writer.WriteAddressAndTags(address, 27948u); m_Writer.Write(element); m_Socket.Send(m_Writer.Buffer, m_Writer.Length, SocketFlags.None); } public void Send(string address, char element) { m_Writer.WriteAddressAndTags(address, 25388u); m_Writer.Write(element); m_Socket.Send(m_Writer.Buffer, m_Writer.Length, SocketFlags.None); } public void Send(string address, bool element) { m_Writer.WriteAddressAndTags(address, element ? 21548u : 17964u); m_Socket.Send(m_Writer.Buffer, m_Writer.Length, SocketFlags.None); } public void SendNil(string address) { m_Writer.WriteAddressAndTags(address, 20012u); m_Socket.Send(m_Writer.Buffer, m_Writer.Length, SocketFlags.None); } public void SendInfinitum(string address) { m_Writer.WriteAddressAndTags(address, 18732u); m_Socket.Send(m_Writer.Buffer, m_Writer.Length, SocketFlags.None); } public void ForceSendBuffer() { m_Socket.Send(m_Writer.Buffer, m_Writer.Length, SocketFlags.None); } private unsafe static uint[] GetAlignedAsciiBytes(string input) { int byteCount = Encoding.ASCII.GetByteCount(input); uint[] array = new uint[((byteCount + 3) & -4) / 4]; fixed (uint* bytes = array) { fixed (char* chars = input) { Encoding.ASCII.GetBytes(chars, input.Length, (byte*)bytes, byteCount); } } return array; } } public class OscParser { public const int MaxElementsPerMessage = 32; public const int MaxBlobSize = 262144; internal readonly byte[] Buffer; internal unsafe readonly byte* BufferPtr; internal unsafe readonly long* BufferLongPtr; public readonly OscMessageValues MessageValues; public unsafe OscParser(byte[] fixedBuffer) { Buffer = fixedBuffer; fixed (byte* ptr = fixedBuffer) { BufferPtr = ptr; BufferLongPtr = (long*)ptr; } MessageValues = new OscMessageValues(Buffer, 32); } public int Parse() { int num = FindUnalignedAddressLength(); if (num < 0) { return num; } int num2 = (num + 3) & -4; if (num2 == num) { num2 += 4; } int num3 = ParseTags(Buffer, num2); int offset = (num2 + (num3 + 4)) & -4; FindOffsets(offset); return num; } public int Parse(int startingByteOffset) { int num = FindUnalignedAddressLength(startingByteOffset); if (num < 0) { return num; } int num2 = (num + 3) & -4; if (num2 == num) { num2 += 4; } int num3 = startingByteOffset + num2; int num4 = ParseTags(Buffer, num3); int offset = (num3 + (num4 + 4)) & -4; FindOffsets(offset); return num; } internal static bool AddressIsValid(string address) { if (address[0] != '/') { return false; } for (int i = 0; i < address.Length; i++) { switch (address[i]) { case ' ': case '#': case '*': case ',': case '?': case '[': case ']': case '{': case '}': return false; } } return true; } internal static bool CharacterIsValidInAddress(char c) { switch (c) { case ' ': case '#': case '*': case ',': case '?': case '[': case ']': case '{': case '}': return false; default: return true; } } internal static AddressType GetAddressType(string address) { if (address[0] != '/') { return AddressType.Invalid; } bool flag = true; string text = address; for (int i = 0; i < text.Length; i++) { switch (text[i]) { case ' ': case '#': case '*': case ',': case '?': case '[': case ']': case '{': case '}': flag = false; break; } } if (flag) { return AddressType.Address; } text = address; foreach (char c in text) { if (c == ' ' || c == '#' || c == ',') { return AddressType.Invalid; } } return AddressType.Pattern; } internal int ParseTags(byte[] bytes, int start = 0) { if (bytes[start] != 44) { return 0; } int num = start + 1; int num2 = 0; TypeTag[] tags = MessageValues.Tags; while (true) { TypeTag typeTag = (TypeTag)bytes[num]; if (!typeTag.IsSupported()) { break; } tags[num2] = typeTag; num++; num2++; } MessageValues.ElementCount = num2; return num2 + 1; } public unsafe int FindUnalignedAddressLength() { if (*BufferPtr != 47) { return -1; } int num = 1; do { num++; } while (BufferPtr[num] != 0); return num; } public unsafe int FindUnalignedAddressLength(int offset) { if (BufferPtr[offset] != 47) { return -1; } int num = offset + 1; do { num++; } while (BufferPtr[num] != 0); return num - offset; } public int GetStringLength(int offset) { int num = Buffer.Length - offset; int i; for (i = offset; i < num && Buffer[i] == 0; i++) { } return (i - offset + 3) & -4; } public unsafe void FindOffsets(int offset) { TypeTag[] tags = MessageValues.Tags; int[] offsets = MessageValues.Offsets; for (int i = 0; i < MessageValues.ElementCount; i++) { offsets[i] = offset; switch (tags[i]) { case TypeTag.AsciiChar32: case TypeTag.Float32: case TypeTag.Int32: case TypeTag.MIDI: case TypeTag.Color32: offset += 4; break; case TypeTag.Float64: case TypeTag.Int64: case TypeTag.TimeTag: offset += 8; break; case TypeTag.AltTypeString: case TypeTag.String: offset += GetStringLength(offset); break; case TypeTag.Blob: offset += 4 + *(int*)(BufferPtr + offset); break; } } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe bool IsBundleTagAtIndex(int index) { return *(long*)(BufferPtr + (nint)index * (nint)8) == Constant.BundlePrefixLong; } public static int FindArrayLength(byte[] bytes, int offset = 0) { if (bytes[offset] != 91) { return -1; } int i; for (i = offset + 1; bytes[i] != 93; i++) { } return i - offset; } } public sealed class OscServer : IDisposable { private static readonly Dictionary<Action<OscMessageValues>, OscActionPair> k_SingleCallbackToPair = new Dictionary<Action<OscMessageValues>, OscActionPair>(); private readonly OscSocket m_Socket; private bool m_Disposed; private bool m_Started; private readonly byte[] m_ReadBuffer; private GCHandle m_BufferHandle; private unsafe byte* m_BufferPtr; private Action[] m_MainThreadQueue = new Action[16]; private int m_MainThreadCount; private readonly Dictionary<int, string> m_ByteLengthToStringBuffer = new Dictionary<int, string>(); private readonly HashSet<MonitorCallback> m_MonitorCallbacks = new HashSet<MonitorCallback>(); private readonly List<OscActionPair> m_PatternMatchedMethods = new List<OscActionPair>(); public static readonly Dictionary<int, OscServer> PortToServer = new Dictionary<int, OscServer>(); internal bool Running { get; set; } public int Port { get; } public OscAddressSpace AddressSpace { get; private set; } public OscParser Parser { get; } public NtpTimestamp LastBundleTimestamp { get; private set; } public unsafe OscServer(int port, int bufferSize = 4096) { if (PortToServer.ContainsKey(port)) { ((MelonBase)Core.Instance).LoggerInstance.Error($"port {port} is already in use, cannot start a new OSC Server on it"); return; } k_SingleCallbackToPair.Clear(); AddressSpace = new OscAddressSpace(); m_ReadBuffer = new byte[bufferSize]; m_BufferHandle = GCHandle.Alloc(m_ReadBuffer, GCHandleType.Pinned); m_BufferPtr = (byte*)(void*)m_BufferHandle.AddrOfPinnedObject(); Parser = new OscParser(m_ReadBuffer); Port = port; m_Socket = new OscSocket(port) { Server = this }; Start(); } public void Start() { if (m_Started) { Running = true; return; } m_Socket.Start(); m_Disposed = false; m_Started = true; Running = true; } public static OscServer GetOrCreate(int port) { if (!PortToServer.TryGetValue(port, out var value)) { value = new OscServer(port); PortToServer[port] = value; } return value; } public static bool Remove(int port) { if (PortToServer.TryGetValue(port, out var value)) { value.Dispose(); return PortToServer.Remove(port); } return false; } public bool TryAddMethod(string address, Action<OscMessageValues> valueReadMethod) { OscActionPair oscActionPair = new OscActionPair(valueReadMethod); k_SingleCallbackToPair.Add(valueReadMethod, oscActionPair); return AddressSpace.TryAddMethod(address, oscActionPair); } public bool RemoveMethod(string address, Action<OscMessageValues> valueReadMethod) { if (k_SingleCallbackToPair.TryGetValue(valueReadMethod, out var value)) { if (AddressSpace.RemoveMethod(address, value)) { return k_SingleCallbackToPair.Remove(valueReadMethod); } return false; } return false; } public bool RemoveAddress(string address) { return AddressSpace.RemoveAddressMethod(address); } public bool TryAddMethodPair(string address, OscActionPair actionPair) { return AddressSpace.TryAddMethod(address, actionPair); } public bool TryAddMethodPair(string address, Action<OscMessageValues> read, Action mainThread) { return AddressSpace.TryAddMethod(address, new OscActionPair(read, mainThread)); } public bool RemoveMethodPair(string address, OscActionPair actionPair) { if (AddressSpace != null) { return AddressSpace.RemoveMethod(address, actionPair); } return true; } public void AddMonitorCallback(MonitorCallback callback) { m_MonitorCallbacks.Add(callback); } public bool RemoveMonitorCallback(MonitorCallback callback) { return m_MonitorCallbacks.Remove(callback); } public void Update() { for (int i = 0; i < m_MainThreadCount; i++) { m_MainThreadQueue[i](); } m_MainThreadCount = 0; } public unsafe void ParseBuffer(int byteLength) { byte* bufferPtr = Parser.BufferPtr; long* bufferLongPtr = Parser.BufferLongPtr; OscParser parser = Parser; OscAddressMethods addressToMethod = AddressSpace.AddressToMethod; if (*bufferLongPtr != Constant.BundlePrefixLong) { int num = parser.Parse(); if (num >= 0) { if (addressToMethod.TryGetValueFromBytes(bufferPtr, num, out var value)) { HandleCallbacks(value, parser.MessageValues); } else if (AddressSpace.PatternCount > 0) { TryMatchPatterns(parser, bufferPtr, num); } Profiler.EndSample(); if (m_MonitorCallbacks.Count > 0) { HandleMonitorCallbacks(bufferPtr, num, parser); } } return; } int num2 = 0; bool flag; do { LastBundleTimestamp = parser.MessageValues.ReadTimestampIndex(num2 + 8); num2 += 16; flag = false; while (num2 < byteLength && !flag) { int num3 = (int)parser.MessageValues.ReadUIntIndex(num2); int num4 = num2 + 4; if (parser.IsBundleTagAtIndex(num4)) { num2 = num4; flag = true; continue; } int num5 = parser.Parse(num4); if (num5 <= 0) { num2 += num3 + 4; continue; } byte* ptr = bufferPtr + num4; if (addressToMethod.TryGetValueFromBytes(ptr, num5, out var value2)) { HandleCallbacks(value2, parser.MessageValues); } else if (AddressSpace.PatternCount > 0) { TryMatchPatterns(parser, bufferPtr, num5); } num2 += num3 + 4; if (m_MonitorCallbacks.Count > 0) { HandleMonitorCallbacks(ptr, num5, parser); } } } while (flag); } private void HandleCallbacks(OscActionPair pair, OscMessageValues messageValues) { pair.ValueRead(messageValues); if (pair.MainThreadQueued != null) { if (m_MainThreadCount >= m_MainThreadQueue.Length) { Array.Resize(ref m_MainThreadQueue, m_MainThreadCount + 16); } m_MainThreadQueue[m_MainThreadCount++] = pair.MainThreadQueued; } } private unsafe void HandleMonitorCallbacks(byte* bufferPtr, int addressLength, OscParser parser) { BlobString address = new BlobString(bufferPtr, addressLength); foreach (MonitorCallback monitorCallback in m_MonitorCallbacks) { monitorCallback(address, parser.MessageValues); } } private unsafe void TryMatchPatterns(OscParser parser, byte* bufferPtr, int addressLength) { if (!m_ByteLengthToStringBuffer.TryGetValue(addressLength, out var value)) { value = Encoding.ASCII.GetString(bufferPtr, addressLength); m_ByteLengthToStringBuffer[addressLength] = value; } else { OverwriteAsciiString(value, bufferPtr); } if (!AddressSpace.TryMatchPatternHandler(value, m_PatternMatchedMethods)) { return; } AddressSpace.AddressToMethod.Add(value, m_PatternMatchedMethods); foreach (OscActionPair patternMatchedMethod in m_PatternMatchedMethods) { patternMatchedMethod.ValueRead(parser.MessageValues); m_MainThreadQueue[m_MainThreadCount++] = patternMatchedMethod.MainThreadQueued; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private unsafe static void OverwriteAsciiString(string str, byte* bufferPtr) { fixed (char* ptr = str) { for (int i = 0; i < str.Length; i++) { ptr[i] = (char)bufferPtr[i]; } } } public void Dispose() { PortToServer.Remove(Port); if (!m_Disposed) { m_Disposed = true; if (m_BufferHandle.IsAllocated) { m_BufferHandle.Free(); } AddressSpace.AddressToMethod.Dispose(); AddressSpace = null; m_Socket.Dispose(); } } ~OscServer() { Dispose(); } public int CountHandlers() { return AddressSpace?.AddressToMethod.SourceToBlob.Count ?? 0; } } internal sealed class OscSocket : IDisposable { private readonly Socket m_Socket; private readonly Thread m_Thread; private bool m_Disposed; private bool m_Started; private AutoResetEvent m_ThreadWakeup; private bool m_CloseRequested; public int Port { get; } public OscServer Server { get; set; } public OscSocket(int port) { Port = port; m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp) { ReceiveTimeout = int.MaxValue }; m_Thread = new Thread(Serve); } public void Start() { if (!m_Started) { m_Disposed = false; if (!m_Socket.IsBound) { m_Socket.Bind(new IPEndPoint(IPAddress.Any, Port)); } m_ThreadWakeup = new AutoResetEvent(initialState: false); m_Thread.Start(); m_Started = true; } } private void Serve() { byte[] buffer = Server.Parser.Buffer; Socket socket = m_Socket; while (!m_Disposed) { try { int receivedByteCount = 0; socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, delegate(IAsyncResult result) { try { receivedByteCount = socket.EndReceive(result); } catch (Exception ex4) { if (!m_Disposed && !m_CloseRequested) { ((MelonBase)Core.Instance).LoggerInstance.Error((object)ex4); } } finally { m_ThreadWakeup.Set(); } }, null); m_ThreadWakeup.WaitOne(); if (m_CloseRequested) { m_Socket.Close(); m_Socket.Dispose(); break; } if (receivedByteCount != 0) { Server.ParseBuffer(receivedByteCount); Profiler.EndSample(); } continue; } catch (SocketException) { continue; } catch (ThreadAbortException) { continue; } catch (Exception ex3) { if (!m_Disposed) { ((MelonBase)Core.Instance).LoggerInstance.Error((object)ex3); } } break; } m_ThreadWakeup.Dispose(); } public void Dispose() { if (!m_Disposed) { if (m_ThreadWakeup != null) { m_CloseRequested = true; m_ThreadWakeup.Set(); } else { m_Socket.Close(); m_Socket.Dispose(); } m_Disposed = true; } } } public sealed class OscWriter : IDisposable { public readonly byte[] Buffer; private unsafe readonly byte* m_BufferPtr; private readonly GCHandle m_BufferHandle; private unsafe readonly MidiMessage* m_BufferMidiPtr; private readonly float[] m_FloatSwap = new float[1]; private unsafe readonly byte* m_FloatSwapPtr; private readonly GCHandle m_FloatSwapHandle; private readonly double[] m_DoubleSwap = new double[1]; private unsafe readonly byte* m_DoubleSwapPtr; private readonly GCHandle m_DoubleSwapHandle; private readonly Color32[] m_Color32Swap = (Color32[])(object)new Color32[1]; private unsafe readonly byte* m_Color32SwapPtr; private readonly GCHandle m_Color32SwapHandle; private int m_Length; public int Length => m_Length; public unsafe OscWriter(int capacity = 4096) { Buffer = new byte[capacity]; m_BufferPtr = Utils.PinPtr<byte, byte>(Buffer, out m_BufferHandle); m_BufferMidiPtr = (MidiMessage*)m_BufferPtr; m_FloatSwapPtr = Utils.PinPtr<float, byte>(m_FloatSwap, out m_FloatSwapHandle); m_DoubleSwapPtr = Utils.PinPtr<double, byte>(m_DoubleSwap, out m_DoubleSwapHandle); m_Color32SwapPtr = Utils.PinPtr<Color32, byte>(m_Color32Swap, out m_Color32SwapHandle); } ~OscWriter() { Dispose(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Reset() { m_Length = 0; } public void Write(int data) { Buffer[m_Length++] = (byte)(data >> 24); Buffer[m_Length++] = (byte)(data >> 16); Buffer[m_Length++] = (byte)(data >> 8); Buffer[m_Length++] = (byte)data; } public unsafe void Write(float data) { m_FloatSwap[0] = data; Buffer[m_Length++] = m_FloatSwapPtr[3]; Buffer[m_Length++] = m_FloatSwapPtr[2]; Buffer[m_Length++] = m_FloatSwapPtr[1]; Buffer[m_Length++] = *m_FloatSwapPtr; } public void Write(Vector2 data) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) Write(data.x); Write(data.y); } public void Write(Vector3 data) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) Write(data.x); Write(data.y); Write(data.z); } public void Write(string data) { foreach (char c in data) { Buffer[m_Length++] = (byte)c; } int num = (data.Length + 3) & -4; if (num == data.Length) { num += 4; } for (int j = data.Length; j < num; j++) { Buffer[m_Length++] = 0; } } public unsafe void Write(BlobString data) { int length = data.Length; System.Buffer.MemoryCopy(data.Handle.Pointer, m_BufferPtr + m_Length, length, length); m_Length += length; int num = (data.Length + 3) & -4; if (num == data.Length) { num += 4; } for (int i = data.Length; i < num; i++) { Buffer[m_Length++] = 0; } } public void Write(byte[] bytes, int length, int start = 0) { if (start + length <= bytes.Length) { Write(length); System.Buffer.BlockCopy(bytes, start, Buffer, m_Length, length); m_Length += length; int num = ((length + 3) & -4) - length; for (int i = 0; i < num; i++) { Buffer[m_Length++] = 0; } } } public void Write(long data) { byte[] buffer = Buffer; buffer[m_Length++] = (byte)(data >> 56); buffer[m_Length++] = (byte)(data >> 48); buffer[m_Length++] = (byte)(data >> 40); buffer[m_Length++] = (byte)(data >> 32); buffer[m_Length++] = (byte)(data >> 24); buffer[m_Length++] = (byte)(data >> 16); buffer[m_Length++] = (byte)(data >> 8); buffer[m_Length++] = (byte)data; } public unsafe void Write(double data) { byte[] buffer = Buffer; m_DoubleSwap[0] = data; byte* doubleSwapPtr = m_DoubleSwapPtr; buffer[m_Length++] = doubleSwapPtr[7]; buffer[m_Length++] = doubleSwapPtr[6]; buffer[m_Length++] = doubleSwapPtr[5]; buffer[m_Length++] = doubleSwapPtr[4]; buffer[m_Length++] = doubleSwapPtr[3]; buffer[m_Length++] = doubleSwapPtr[2]; buffer[m_Length++] = doubleSwapPtr[1]; buffer[m_Length++] = *doubleSwapPtr; } public unsafe void Write(Color32 data) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) m_Color32Swap[0] = data; Buffer[m_Length++] = m_Color32SwapPtr[3]; Buffer[m_Length++] = m_Color32SwapPtr[2]; Buffer[m_Length++] = m_Color32SwapPtr[1]; Buffer[m_Length++] = *m_Color32SwapPtr; } public unsafe void Write(MidiMessage data) { MidiMessage* ptr = (MidiMessage*)(m_BufferPtr + m_Length); *ptr = data; m_Length += 4; } public unsafe void Write(NtpTimestamp time) { time.ToBigEndianBytes((uint*)(m_BufferPtr + m_Length)); m_Length += 8; } public unsafe void WriteCurrentTimestamp() { new NtpTimestamp(DateTime.Now).ToBigEndianBytes((uint*)(m_BufferPtr + m_Length)); m_Length += 8; } public void Write(char data) { Buffer[m_Length + 3] = (byte)data; m_Length += 4; } public void WriteBundlePrefix() { System.Buffer.BlockCopy(Constant.BundlePrefixBytes, 0, Buffer, m_Length, 8); m_Length += 8; } public unsafe void WriteAddressAndTags(string address, uint tags) { m_Length = 0; foreach (char c in address) { Buffer[m_Length++] = (byte)c; } int num = (address.Length + 3) & -4; if (num == address.Length) { num += 4; } for (int j = address.Length; j < num; j++) { Buffer[m_Length++] = 0; } *(uint*)(m_BufferPtr + m_Length) = tags; m_Length += 4; } public void CopyBuffer(byte[] copyTo, int copyOffset = 0) { System.Buffer.BlockCopy(Buffer, 0, copyTo, copyOffset, Length); } public void Dispose() { m_BufferHandle.SafeFree(); m_Color32SwapHandle.SafeFree(); m_FloatSwapHandle.SafeFree(); m_DoubleSwapHandle.SafeFree(); } } [StructLayout(LayoutKind.Explicit)] public struct MidiMessage : IEquatable<MidiMessage> { [FieldOffset(0)] private readonly int data; [FieldOffset(0)] public readonly byte PortId; [FieldOffset(1)] public readonly byte Status; [FieldOffset(2)] public readonly byte Data1; [FieldOffset(3)] public readonly byte Data2; public MidiMessage(byte[] bytes, int offset) { data = 0; PortId = bytes[offset]; Status = bytes[offset + 1]; Data1 = bytes[offset + 2]; Data2 = bytes[offset + 3]; } public MidiMessage(byte portId, byte status, byte data1, byte data2) { data = 0; PortId = portId; Status = status; Data1 = data1; Data2 = data2; } public override string ToString() { return $"Port ID: {PortId}, Status: {Status}, Data 1: {Data1} , 2: {Data2}"; } public bool Equals(MidiMessage other) { if (PortId == other.PortId && Status == other.Status && Data1 == other.Data1) { return Data2 == other.Data2; } return false; } public override bool Equals(object obj) { if (obj is MidiMessage other) { return Equals(other); } return false; } public override int GetHashCode() { return (((Status.GetHashCode() * 397) ^ Data1.GetHashCode()) * 397) ^ Data2.GetHashCode(); } public static bool operator ==(MidiMessage left, MidiMessage right) { return left.Equals(right); } public static bool operator !=(MidiMessage left, MidiMessage right) { return !left.Equals(right); } } internal static class ExtensionMethods { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Align4(this int self) { return (self + 3) & -4; } internal static void SafeFree(this GCHandle handle) { if (handle.IsAllocated) { handle.Free(); } } internal static int ClampPort(this int port) { if (port < 1024) { port = 1024; } if (port >= 65535) { port = 65535; } return port; } } internal sealed class OscAddressMethods : IDisposable { private const int defaultSize = 16; public readonly Dictionary<BlobHandle, OscActionPair> HandleToValue; internal readonly Dictionary<string, BlobString> SourceToBlob; public OscAddressMethods(int initialCapacity = 16) { HandleToValue = new Dictionary<BlobHandle, OscActionPair>(initialCapacity); SourceToBlob = new Dictionary<string, BlobString>(initialCapacity); } public void Add(string address, OscActionPair callbacks) { if (!SourceToBlob.TryGetValue(address, out var value)) { value = new BlobString(address, (Allocator)4); HandleToValue[value.Handle] = callbacks; SourceToBlob.Add(address, value); } else if (HandleToValue.ContainsKey(value.Handle)) { HandleToValue[value.Handle] += callbacks; } else { HandleToValue[value.Handle] = callbacks; } } public void Add(string address, Action<OscMessageValues> callback) { Add(address, new OscActionPair(callback)); } internal void Add(string address, List<OscActionPair> callbacks) { if (callbacks.Count == 0) { return; } OscActionPair callbacks2 = callbacks[0]; if (callbacks.Count > 1) { for (int i = 1; i < callbacks.Count; i++) { callbacks2 += callbacks[i]; } } Add(address, callbacks2); } public bool Remove(string address, OscActionPair callbacks) { if (!SourceToBlob.TryGetValue(address, out var value)) { return false; } if (!HandleToValue.TryGetValue(value.Handle, out var value2)) { return false; } if (value2.ValueRead.GetInvocationList().Length == 1) { bool result = HandleToValue.Remove(value.Handle) && SourceToBlob.Remove(address); value.Dispose(); return result; } HandleToValue[value.Handle] -= callbacks; return true; } public bool RemoveAddress(string address) { if (!SourceToBlob.TryGetValue(address, out var value)) { return false; } SourceToBlob.Remove(address); HandleToValue.Remove(value.Handle); value.Dispose(); return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe bool TryGetValueFromBytes(byte* ptr, int byteCount, out OscActionPair value) { return HandleToValue.TryGetValue(new BlobHandle(ptr, byteCount), out value); } public void Clear() { HandleToValue.Clear(); SourceToBlob.Clear(); } public void Dispose() { foreach (KeyValuePair<string, BlobString> item in SourceToBlob) { item.Value.Dispose(); } } } internal static class Utils { private static readonly List<char> k_TempChars = new List<char>(); private static readonly StringBuilder k_Builder = new StringBuilder(); public static bool ValidateAddress(ref string address) { if (string.IsNullOrEmpty(address)) { address = "/"; } if (address[0] != '/') { address = address.Insert(0, "/"); } if (address.EndsWith(" ")) { address = address.TrimEnd(' '); } address = ReplaceInvalidAddressCharacters(address); return true; } internal static string ReplaceInvalidAddressCharacters(string address) { k_TempChars.Clear(); k_TempChars.AddRange(address.Where(OscParser.CharacterIsValidInAddress)); return new string(k_TempChars.ToArray()); } public unsafe static TPtr* PinPtr<TData, TPtr>(TData[] array, out GCHandle handle) where TData : struct where TPtr : struct { handle = GCHandle.Alloc(array, GCHandleType.Pinned); return (TPtr*)(void*)handle.AddrOfPinnedObject(); } internal static string GetLocalIpAddress() { string result = "unknown"; IPAddress[] addressList = Dns.GetHostEntry(Dns.GetHostName()).AddressList; foreach (IPAddress iPAddress in addressList) { if (iPAddress.AddressFamily == AddressFamily.InterNetwork) { result = iPAddress.ToString(); break; } } return result; } public static string MonitorMessageToString(BlobString address, OscMessageValues values) { k_Builder.Clear(); k_Builder.Append(address.ToString()); k_Builder.Append(" ,"); values.ForEachElement(delegate(int i, TypeTag type) { k_Builder.Append((char)type); }); k_Builder.Append(" "); int lastIndex = values.ElementCount - 1; values.ForEachElement(delegate(int i, TypeTag type) { string value = values.ReadStringElement(i); k_Builder.Append(value); if (i != lastIndex) { k_Builder.Append(' '); } }); return k_Builder.ToString(); } } } namespace OscCore.Demo { public class MonitorToDebugText : MonoBehaviour { private const int k_LineCount = 9; private const int k_LastIndex = 8; private static readonly StringBuilder k_StringBuilder = new StringBuilder(); public OscReceiver Receiver; public TextMesh IpAddressText; public TextMesh RecentValueText; private int m_ReplaceLineIndex; private bool m_Dirty; private readonly string[] m_ReceivedAsString = new string[9]; public void Awake() { IpAddressText.text = $"Local IP: {Utils.GetLocalIpAddress()} , Port {Receiver.Port}"; Receiver.Server.AddMonitorCallback(Monitor); } private void Update() { if (m_Dirty) { RecentValueText.text = BuildMultiLine(); m_Dirty = false; } } private void Monitor(BlobString address, OscMessageValues values) { m_Dirty = true; if (m_ReplaceLineIndex == 8) { for (int i = 0; i < 8; i++) { m_ReceivedAsString[i] = m_ReceivedAsString[i + 1]; } } m_ReceivedAsString[m_ReplaceLineIndex] = Utils.MonitorMessageToString(address, values); if (m_ReplaceLineIndex < 8) { m_ReplaceLineIndex++; } } private string BuildMultiLine() { k_StringBuilder.Clear(); for (int i = 0; i <= m_ReplaceLineIndex; i++) { k_StringBuilder.AppendLine(m_ReceivedAsString[i]); k_StringBuilder.AppendLine(); } return k_StringBuilder.ToString(); } } } namespace MiniNtp { public static class ExtensionMethods { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint ReverseBytes(this uint value) { return ((value & 0xFF) << 24) | ((value & 0xFF00) << 8) | ((value & 0xFF0000) >> 8) | ((value & 0xFF000000u) >> 24); } } public struct NtpTimestamp : IEquatable<NtpTimestamp>, IComparable<NtpTimestamp> { public readonly uint Seconds; public readonly uint Fractions; public NtpTimestamp(uint seconds, uint fractions) { Seconds = seconds; Fractions = fractions; } public NtpTimestamp(DateTime dt) { DateTime dateTime = ((dt < TimeConstants.Epoch2036) ? TimeConstants.Epoch1900 : TimeConstants.Epoch2036); Seconds = (uint)(dt - dateTime).TotalSeconds; Fractions = (uint)(dt.Millisecond * 5000000); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static NtpTimestamp FromBigEndianBytes(byte[] buffer, int offset) { fixed (byte* tsPtr = &buffer[offset]) { return FromBigEndianBytes((uint*)tsPtr); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static NtpTimestamp FromBigEndianBytes(byte* tsPtr) { return FromBigEndianBytes((uint*)tsPtr); } public unsafe static NtpTimestamp FromBigEndianBytes(uint* tsPtr) { uint num = *tsPtr; uint seconds = ((num & 0xFF) << 24) | ((num & 0xFF00) << 8) | ((num & 0xFF0000) >> 8) | ((num & 0xFF000000u) >> 24); uint num2 = tsPtr[1]; uint fractions = ((num2 & 0xFF) << 24) | ((num2 & 0xFF00) << 8) | ((num2 & 0xFF0000) >> 8) | ((num2 & 0xFF000000u) >> 24); return new NtpTimestamp(seconds, fractions); } public DateTime ToDateTime() { if (Fractions == 1 && Seconds == 0) { return DateTime.Now; } DateTime dateTime = ((DateTime.Now < TimeConstants.Epoch2036) ? TimeConstants.Epoch1900 : TimeConstants.Epoch2036); double num = (double)Fractions * 2E-07; double value = (double)Seconds * 1000.0 + num; return dateTime.AddMilliseconds(value); } public unsafe void ToBigEndianBytes(byte[] bytes, int offset) { fixed (byte* ptr = &bytes[offset]) { uint* ptr2 = (uint*)ptr; *ptr2 = Seconds.ReverseBytes(); ptr2[1] = Fractions.ReverseBytes(); } } public unsafe void ToBigEndianBytes(uint* writePtr) { *writePtr = Seconds.ReverseBytes(); writePtr[1] = Fractions.ReverseBytes(); } public override string ToString() { return $"Seconds: {Seconds} , Fractions {Fractions}"; } public bool Equals(NtpTimestamp other) { if (Seconds == other.Seconds) { return Fractions == other.Fractions; } return false; } public override bool Equals(object obj) { if (obj is NtpTimestamp other) { return Equals(other); } return false; } public override int GetHashCode() { return (int)((Seconds * 397) ^ Fractions); } public static bool operator ==(NtpTimestamp left, NtpTimestamp right) { return left.Equals(right); } public static bool operator !=(NtpTimestamp left, NtpTimestamp right) { return !left.Equals(right); } public int CompareTo(NtpTimestamp other) { int num = Seconds.CompareTo(other.Seconds); if (num == 0) { return Fractions.CompareTo(other.Fractions); } return num; } public static bool operator <(NtpTimestamp left, NtpTimestamp right) { return left.CompareTo(right) < 0; } public static bool operator >(NtpTimestamp left, NtpTimestamp right) { return left.CompareTo(right) > 0; } public static bool operator <=(NtpTimestamp left, NtpTimestamp right) { return left.CompareTo(right) <= 0; } public static bool operator >=(NtpTimestamp left, NtpTimestamp right) { return left.CompareTo(right) >= 0; } public static NtpTimestamp operator -(NtpTimestamp left, NtpTimestamp right) { return new NtpTimestamp(left.Seconds - right.Seconds, left.Fractions - right.Fractions); } } public static class TimeConstants { public static readonly DateTime Epoch1900 = DateTime.Parse("1900-01-01 00:00:00.000"); public static readonly DateTime Epoch2036 = DateTime.Parse("2036-02-07 06:28:15"); public const int TicksPerSecond = 10000000; public const uint TimestampFractionsPerMs = 5000000u; public const double FractionMillisecondMultiplier = 2E-07; } } namespace BlobHandles { public static class BlobHandleDictionaryMethods { [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static bool TryGetValueFromBytes<T>(this Dictionary<BlobHandle, T> self, byte* ptr, int length, out T value) { return self.TryGetValue(new BlobHandle(ptr, length), out value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryGetValueFromBytes<T>(this Dictionary<BlobHandle, T> self, byte[] bytes, out T value) { return self.TryGetValue(new BlobHandle(bytes), out value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryGetValueFromBytes<T>(this Dictionary<BlobHandle, T> self, byte[] bytes, int length, out T value) { return self.TryGetValue(new BlobHandle(bytes, length), out value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryGetValueFromBytes<T>(this Dictionary<BlobHandle, T> self, byte[] bytes, int length, int offset, out T value) { return self.TryGetValue(new BlobHandle(bytes, length, offset), out value); } } public static class BlobHandleHashSetMethods { [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static bool ContainsBlob<T>(this HashSet<BlobHandle> self, byte* ptr, int length) { return self.Contains(new BlobHandle(ptr, length)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ContainsBlob<T>(this HashSet<BlobHandle> self, byte[] bytes) { return self.Contains(new BlobHandle(bytes)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ContainsBlob<T>(this HashSet<BlobHandle> self, byte[] bytes, int length) { return self.Contains(new BlobHandle(bytes, length)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool ContainsBlob(this HashSet<BlobHandle> self, byte[] bytes, int length, int offset) { return self.Contains(new BlobHandle(bytes, length, offset)); } } public sealed class BlobStringDictionary<T> : IDisposable { private const int defaultSize = 16; public readonly Dictionary<BlobHandle, T> HandleToValue; private readonly Dictionary<string, BlobString> SourceToBlob; public BlobStringDictionary(int initialCapacity = 16) { HandleToValue = new Dictionary<BlobHandle, T>(initialCapacity); SourceToBlob = new Dictionary<string, BlobString>(initialCapacity); } public void Add(string str, T value) { if (str != null && !SourceToBlob.ContainsKey(str)) { BlobString value2 = new BlobString(str, (Allocator)4); HandleToValue.Add(value2.Handle, value); SourceToBlob.Add(str, value2); } } public void Add(BlobString blobStr, T value) { HandleToValue.Add(blobStr.Handle, value); } public bool Remove(string str) { if (!SourceToBlob.TryGetValue(str, out var value)) { return false; } SourceToBlob.Remove(str); bool result = HandleToValue.Remove(value.Handle); value.Dispose(); return result; } public bool Remove(BlobString blobStr) { return HandleToValue.Remove(blobStr.Handle); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe bool TryGetValueFromBytes(byte* ptr, int byteCount, out T value) { return HandleToValue.TryGetValue(new BlobHandle(ptr, byteCount), out value); } public void Clear() { HandleToValue.Clear(); SourceToBlob.Clear(); } public void Dispose() { foreach (KeyValuePair<string, BlobString> item in SourceToBlob) { item.Value.Dispose(); } } } public struct BlobHandle : IEquatable<BlobHandle> { public unsafe readonly byte* Pointer; public readonly int Length; public unsafe BlobHandle(byte* pointer, int length) { Pointer = pointer; Length = length; } public unsafe BlobHandle(IntPtr pointer, int length) { Pointer = (byte*)(void*)pointer; Length = length; } public unsafe BlobHandle(byte[] bytes) { fixed (byte* pointer = bytes) { Pointer = pointer; Length = bytes.Length; } } public unsafe BlobHandle(byte[] bytes, int length) { fixed (byte* pointer = bytes) { Pointer = pointer; Length = length; } } public unsafe BlobHandle(byte[] bytes, int length, int offset) { fixed (byte* pointer = &bytes[offset]) { Pointer = pointer; Length = length; } } public unsafe override string ToString() { return Length + " bytes @ " + new IntPtr(Pointer); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe override int GetHashCode() { return (Length * 397) ^ Pointer[Length - 1]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe bool Equals(BlobHandle other) { if (Length == other.Length) { return MemoryCompare(Pointer, other.Pointer, (UIntPtr)(ulong)Length) == 0; } return false; } public override bool Equals(object obj) { if (obj is BlobHandle other) { return Equals(other); } return false; } public unsafe static bool operator ==(BlobHandle left, BlobHandle right) { if (left.Length == right.Length) { return MemoryCompare(left.Pointer, right.Pointer, (UIntPtr)(ulong)left.Length) == 0; } return false; } public unsafe static bool operator !=(BlobHandle left, BlobHandle right) { if (left.Length == right.Length) { return MemoryCompare(left.Pointer, right.Pointer, (UIntPtr)(ulong)left.Length) != 0; } return true; } private unsafe static int MemoryCompare(void* ptr1, void* ptr2, UIntPtr count) { Span<byte> span = new Span<byte>(ptr1, (int)(uint)count); Span<byte> span2 = new Span<byte>(ptr2, (int)(uint)count); for (int i = 0; i < span.Length; i++) { if (span[i] != span2[i]) { return 1; } } return 0; } } public struct BlobString : IDisposable, IEquatable<BlobString> { private readonly NativeArray<byte> Bytes; public readonly BlobHandle Handle; public static Encoding Encoding { get; set; } = Encoding.ASCII; public int Length => Bytes.Length; public unsafe BlobString(string source, Allocator allocator = 4) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) int byteCount = Encoding.GetByteCount(source); Bytes = new NativeArray<byte>(byteCount, allocator, (NativeArrayOptions)1); byte* unsafePtr = (byte*)NativeArrayUnsafeUtility.GetUnsafePtr<byte>(Bytes); fixed (char* chars = source) { Encoding.GetBytes(chars, source.Length, unsafePtr, byteCount); Handle = new BlobHandle(unsafePtr, byteCount); } } public unsafe BlobString(byte* sourcePtr, int length) { Handle = new BlobHandle(sourcePtr, length); Bytes = null; } public unsafe override string ToString() { return Encoding.GetString(Handle.Pointer, Handle.Length); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { return Handle.GetHashCode(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(BlobString other) { return Handle.Equals(other.Handle); } public override bool Equals(object obj) { if (obj is BlobString blobString) { return Handle.Equals(blobString.Handle); } return false; } public static bool operator ==(BlobString l, BlobString r) { return l.Handle == r.Handle; } public static bool operator !=(BlobString l, BlobString r) { return l.Handle != r.Handle; } public void Dispose() { if (Bytes.IsCreated) { Bytes.Dispose(); } } } } namespace EyeTracking { internal static class BuildInfo { internal const string Name = "EyeTracking"; internal const string Version = "0.0.1"; internal const string Author = "Checkerboard"; internal const string GameDeveloper = "Stress Level Zero"; internal const string GameName = "BONELAB"; } public class Core : MelonMod { internal static Core Instance { get; private set; } internal PreferencesManager PreferencesManager { get; private set; } internal TrackingProviderManager TrackingProviderManager { get; private set; } internal BoneMenuManager BoneMenuManager { get; private set; } internal SolverManager SolverManager { get; private set; } public override void OnInitializeMelon() { Instance = this; PreferencesManager = new PreferencesManager(); TrackingProviderManager = new TrackingProviderManager(); BoneMenuManager = new BoneMenuManager(); SolverManager = new SolverManager(); FusionModuleManager.TryLoadModule(out var _); } public override void OnUpdate() { if (PreferencesManager.Enabled.Value) { BoneMenuManager.Update(); SolverManager.Update(); } } } public static class Tracking { public static readonly EyeData EyeData = new EyeData(); public static readonly FaceData FaceData = new FaceData(); public static bool IsTracking { get { if (Core.Instance.TrackingProviderManager.CurrentProvider != null) { return Core.Instance.TrackingProviderManager.CurrentProvider.IsLoaded; } return false; } } public static bool SupportsEye => Core.Instance.TrackingProviderManager.CurrentProvider.SupportsEye; public static bool SupportsFace => Core.Instance.TrackingProviderManager.CurrentProvider.SupportsFace; } } namespace EyeTracking.Utilities { internal static class AssemblyUtilities { internal static void LoadAllValid<T>(Assembly assembly, Action<Type> runOnValid) { Type[] types; try { types = assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { types = ex.Types; } Type[] array = types; foreach (Type type in array) { if (type == null || (type.Name.Contains("Mono") && type.Name.Contains("Security"))) { continue; } bool flag = false; try { flag = typeof(T).IsAssignableFrom(type); } catch { continue; } if (flag && !type.IsAbstract && !type.IsInterface) { try { runOnValid(type); } catch (Exception ex2) { ((MelonBase)Core.Instance).LoggerInstance.Error(ex2.Message); } } } } } internal static class EmbeddedResourceUtilities { internal static byte[] LoadBytesFromAssembly(Assembly assembly, string name) { if (!((ReadOnlySpan<string>)assembly.GetManifestResourceNames()).Contains(name)) { return null; } using Stream stream = assembly.GetManifestResourceStream(name); using MemoryStream memoryStream = new MemoryStream(); stream?.CopyTo(memoryStream); return memoryStream.ToArray(); } } public static class UnityUtilities { public static Vector2 FlipXCoordinates(this Vector2 vector) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) vector.x *= -1f; return vector; } public static Vector2 FlipYCoordinates(this Vector2 vector) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) vector.y *= -1f; return vector; } } } namespace EyeTracking.UserData { internal class PreferencesManager { private MelonPreferences_Category Category { get; set; } internal MelonPreferences_Entry<bool> Enabled { get; private set; } internal MelonPreferences_Entry<string> TrackingProvider { get; private set; } internal PreferencesManager() { Category = MelonPreferences.CreateCategory("EyeTracking"); Enabled = Category.CreateEntry<bool>("Enabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); TrackingProvider = Category.CreateEntry<string>("TrackingProvider", "VRCFT", (string)null, (string)null, false, false, (ValueValidator)null, (string)null); Save(); } internal void SetProvider(string provider) { TrackingProvider.Value = provider; Save(); } internal void Save() { Category.SaveToFile(false); } } } namespace EyeTracking.TrackingProviders { internal class Babble : TrackingProvider { private bool _isLoaded; private OscReceiver _oscReceiver; private OscSender _oscSender; public override string Name => "Babble"; public override bool IsLoaded => _isLoaded; public override bool SupportsEye => true; public override bool SupportsFace => false; public override void Initialize() { try { _oscReceiver = new OscReceiver(8888); _oscSender = new OscSender(8889); BindEyeAddresses(); _isLoaded = true; } catch (Exception value) { ((MelonBase)Core.Instance).LoggerInstance.Error($"Failed to initialize Babble tracking provider: {value}"); _isLoaded = false; } } public override void Update() { if (_isLoaded) { _oscReceiver.Update(); } } private void BindEyeAddresses() { OscServer server = _oscReceiver.Server; EyeData eye = Tracking.EyeData; if (server != null) { server.TryAddMethod("/LeftEyeX", delegate(OscMessageValues values) { eye.Left.GazeX = values.ReadFloatElement(0); }); server.TryAddMethod("/LeftEyeY", delegate(OscMessageValues values) { eye.Left.GazeY = values.ReadFloatElement(0); }); server.TryAddMethod("/LeftEyeLid", delegate(OscMessageValues values) { eye.Left.Openness = values.ReadFloatElement(0); }); server.TryAddMethod("/RightEyeX", delegate(OscMessageValues values) { eye.Right.GazeX = values.ReadFloatElement(0); }); server.TryAddMethod("/RightEyeY", delegate(OscMessageValues values) { eye.Right.GazeY = values.ReadFloatElement(0); }); server.TryAddMethod("/RightEyeLid", delegate(OscMessageValues values) { eye.Right.Openness = values.ReadFloatElement(0); }); eye.Left.PupilDiameterMm = 2f; eye.Right.PupilDiameterMm = 2f; eye.MinDilation = 0f; eye.MaxDilation = 10f; } } } public abstract class TrackingProvider { public abstract string Name { get; } public abstract bool IsLoaded { get; } public abstract bool SupportsEye { get; } public abstract bool SupportsFace { get; } public abstract void Initialize(); public abstract void Update(); } internal class TrackingProviderManager { internal readonly List<TrackingProvider> providers = new List<TrackingProvider>(); private static readonly string[] blackListedAssemblyNames = new string[2] { "Il2Cpp", "Unity" }; private Thread _trackingThread; private volatile bool _trackingThreadRunning; internal TrackingProvider CurrentProvider { get; private set; } internal TrackingProviderManager() { LoadProviders(); if (!LoadProvider(Core.Instance.PreferencesManager.TrackingProvider.Value)) { LoadFallbackProvider(); } StartThread(); } private void LoadProviders() { providers.Clear(); CurrentProvider = null; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (!blackListedAssemblyNames.Any((string blackListedName) => assembly.FullName != null && assembly.FullName.Contains(blackListedName))) { AssemblyUtilities.LoadAllValid<TrackingProvider>(assembly, RegisterProvider); } } void RegisterProvider(Type type) { if (Activator.CreateInstance(type) is TrackingProvider item) { providers.Add(item); } } } private bool LoadProvider(string name) { TrackingProvider trackingProvider = providers.FirstOrDefault((TrackingProvider p) => p.Name == name); if (trackingProvider == null) { return false; } CurrentProvider = trackingProvider; CurrentProvider.Initialize(); return true; } private void LoadFallbackProvider() { Core.Instance.PreferencesManager.SetProvider(Core.Instance.PreferencesManager.TrackingProvider.DefaultValue); LoadProvider(Core.Instance.PreferencesManager.TrackingProvider.Value); } internal void StartThread() { _trackingThreadRunning = true; _trackingThread = new Thread((ThreadStart)delegate { while (_trackingThreadRunning) { CurrentProvider.Update(); Thread.Sleep(10); } }) { Name = "EyeTracking_ProviderThread", IsBackground = true }; _trackingThread.Start(); } } internal class VRCFT : TrackingProvider { private bool _isLoaded; private OscReceiver _oscReceiver; private OscSender _oscSender; public override string Name => "VRCFT"; public override bool IsLoaded => _isLoaded; public override bool SupportsEye => true; public override bool SupportsFace => true; public override void Initialize() { try { _oscReceiver = new OscReceiver(); _oscSender = new OscSender(9001); CreateVRCAvatar(); _oscSender.Client.Send("/avatar/change", "BONELABEyeTrackingPleaseHelpThisSolutionSucks"); BindEyeAddresses(); BindFaceAddresses(); _isLoaded = true; } catch (Exception value) { ((MelonBase)Core.Instance).LoggerInstance.Error($"Failed to initialize VRCFT tracking provider: {value}"); _isLoaded = false; } } public override void Update() { if (_isLoaded) { _oscReceiver.Update(); } } private void CreateVRCAvatar() { string text = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "Low", "VRChat", "VRChat", "OSC"); if (!Directory.Exists(text)) { Directory.CreateDirectory(text); } string[] directories = Directory.GetDirectories(text); string text2; if (directories.Length != 0) { text2 = directories[0]; } else { text2 = Path.Combine(text, "usr_" + Guid.NewGuid()); Directory.CreateDirectory(text2); } string text3 = Path.Combine(text2, "Avatars"); if (!Directory.Exists(text3)) { Directory.CreateDirectory(text3); } string path = Path.Combine(text3, "BONELABEyeTrackingPleaseHelpThisSolutionSucks.json"); using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("EyeTracking.Resources.BONELABEyeTrackingPleaseHelpThisSolutionSucks.json"); if (stream != null) { using (StreamReader streamReader = new StreamReader(stream)) { string contents = streamReader.ReadToEnd(); File.WriteAllText(path, contents); return; } } } private void BindEyeAddresses() { OscServer server = _oscReceiver.Server; EyeData eye = Tracking.EyeData; if (server != null) { server.TryAddMethod("/avatar/parameters/v2/EyeY", delegate(OscMessageValues values) { float gazeY = values.ReadFloatElement(0); eye.Left.GazeY = gazeY; eye.Right.GazeY = gazeY; }); server.TryAddMethod("/avatar/parameters/v2/EyeLeftX", delegate(OscMessageValues values) { eye.Left.GazeX = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/EyeRightX", delegate(OscMessageValues values) { eye.Right.GazeX = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/EyeOpenLeft", delegate(OscMessageValues values) { eye.Left.Openness = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/EyeOpenRight", delegate(OscMessageValues values) { eye.Right.Openness = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/PupilDiameterLeft", delegate(OscMessageValues values) { eye.Left.PupilDiameterMm = values.ReadFloatElement(0) * 10f; }); server.TryAddMethod("/avatar/parameters/v2/PupilDiameterRight", delegate(OscMessageValues values) { eye.Right.PupilDiameterMm = values.ReadFloatElement(0) * 10f; }); eye.MinDilation = 0f; eye.MaxDilation = 10f; } } private void BindFaceAddresses() { OscServer server = _oscReceiver.Server; FaceData face = Tracking.FaceData; if (server != null) { server.TryAddMethod("/avatar/parameters/v2/EyeLidRight", delegate(OscMessageValues values) { face.EyeLidRight = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/EyeLidLeft", delegate(OscMessageValues values) { face.EyeLidLeft = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/EyeLid", delegate(OscMessageValues values) { face.EyeLid = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/EyeSquintRight", delegate(OscMessageValues values) { face.EyeSquintRight = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/EyeSquintLeft", delegate(OscMessageValues values) { face.EyeSquintLeft = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/EyeSquint", delegate(OscMessageValues values) { face.EyeSquint = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/BrowPinchRight", delegate(OscMessageValues values) { face.BrowPinchRight = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/BrowPinchLeft", delegate(OscMessageValues values) { face.BrowPinchLeft = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/BrowLowererRight", delegate(OscMessageValues values) { face.BrowLowererRight = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/BrowLowererLeft", delegate(OscMessageValues values) { face.BrowLowererLeft = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/BrowInnerUpRight", delegate(OscMessageValues values) { face.BrowInnerUpRight = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/BrowInnerUpLeft", delegate(OscMessageValues values) { face.BrowInnerUpLeft = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/BrowOuterUpRight", delegate(OscMessageValues values) { face.BrowOuterUpRight = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/BrowOuterUpLeft", delegate(OscMessageValues values) { face.BrowOuterUpLeft = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/NoseSneerRight", delegate(OscMessageValues values) { face.NoseSneerRight = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/NoseSneerLeft", delegate(OscMessageValues values) { face.NoseSneerLeft = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/NasalDilationRight", delegate(OscMessageValues values) { face.NasalDilationRight = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/NasalDilationLeft", delegate(OscMessageValues values) { face.NasalDilationLeft = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/NasalConstrictRight", delegate(OscMessageValues values) { face.NasalConstrictRight = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/NasalConstrictLeft", delegate(OscMessageValues values) { face.NasalConstrictLeft = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/CheekSquintRight", delegate(OscMessageValues values) { face.CheekSquintRight = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/CheekSquintLeft", delegate(OscMessageValues values) { face.CheekSquintLeft = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/CheekPuffSuckRight", delegate(OscMessageValues values) { face.CheekPuffSuckRight = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/CheekPuffSuckLeft", delegate(OscMessageValues values) { face.CheekPuffSuckLeft = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/JawOpen", delegate(OscMessageValues values) { face.JawOpen = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/MouthClosed", delegate(OscMessageValues values) { face.MouthClosed = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/JawX", delegate(OscMessageValues values) { face.JawX = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/JawZ", delegate(OscMessageValues values) { face.JawZ = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/JawClench", delegate(OscMessageValues values) { face.JawClench = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/JawMandibleRaise", delegate(OscMessageValues values) { face.JawMandibleRaise = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/LipSuckUpperRight", delegate(OscMessageValues values) { face.LipSuckUpperRight = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/LipSuckUpperLeft", delegate(OscMessageValues values) { face.LipSuckUpperLeft = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/LipSuckLowerRight", delegate(OscMessageValues values) { face.LipSuckLowerRight = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/LipSuckLowerLeft", delegate(OscMessageValues values) { face.LipSuckLowerLeft = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/LipSuckCornerRight", delegate(OscMessageValues values) { face.LipSuckCornerRight = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/LipSuckCornerLeft", delegate(OscMessageValues values) { face.LipSuckCornerLeft = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/LipFunnelUpperRight", delegate(OscMessageValues values) { face.LipFunnelUpperRight = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/LipFunnelUpperLeft", delegate(OscMessageValues values) { face.LipFunnelUpperLeft = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/LipFunnelLowerRight", delegate(OscMessageValues values) { face.LipFunnelLowerRight = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/LipFunnelLowerLeft", delegate(OscMessageValues values) { face.LipFunnelLowerLeft = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/LipPuckerUpperRight", delegate(OscMessageValues values) { face.LipPuckerUpperRight = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/LipPuckerUpperLeft", delegate(OscMessageValues values) { face.LipPuckerUpperLeft = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/LipPuckerLowerRight", delegate(OscMessageValues values) { face.LipPuckerLowerRight = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/LipPuckerLowerLeft", delegate(OscMessageValues values) { face.LipPuckerLowerLeft = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/MouthUpperUpRight", delegate(OscMessageValues values) { face.MouthUpperUpRight = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/MouthUpperUpLeft", delegate(OscMessageValues values) { face.MouthUpperUpLeft = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/MouthLowerDownRight", delegate(OscMessageValues values) { face.MouthLowerDownRight = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/MouthLowerDownLeft", delegate(OscMessageValues values) { face.MouthLowerDownLeft = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/MouthUpperDeepenRight", delegate(OscMessageValues values) { face.MouthUpperDeepenRight = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/MouthUpperDeepenLeft", delegate(OscMessageValues values) { face.MouthUpperDeepenLeft = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/MouthUpperX", delegate(OscMessageValues values) { face.MouthUpperX = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/MouthLowerX", delegate(OscMessageValues values) { face.MouthLowerX = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/MouthCornerPullRight", delegate(OscMessageValues values) { face.MouthCornerPullRight = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/MouthCornerPullLeft", delegate(OscMessageValues values) { face.MouthCornerPullLeft = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/MouthCornerSlantRight", delegate(OscMessageValues values) { face.MouthCornerSlantRight = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/MouthCornerSlantLeft", delegate(OscMessageValues values) { face.MouthCornerSlantLeft = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/MouthDimpleRight", delegate(OscMessageValues values) { face.MouthDimpleRight = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/MouthDimpleLeft", delegate(OscMessageValues values) { face.MouthDimpleLeft = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/MouthFrownRight", delegate(OscMessageValues values) { face.MouthFrownRight = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/MouthFrownLeft", delegate(OscMessageValues values) { face.MouthFrownLeft = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/MouthStretchRight", delegate(OscMessageValues values) { face.MouthStretchRight = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/MouthStretchLeft", delegate(OscMessageValues values) { face.MouthStretchLeft = values.ReadFloatElement(0); }); server.TryAddMethod("/avatar/parameters/v2/MouthRaiserUpper", delegate(OscMessageValues values) { face.MouthRaiserUpper = values.ReadFloatElement(0);