Decompiled source of EyeTracking v1.0.1
Mods/EyeTracking.dll
Decompiled 3 weeks 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.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.Data; using EyeTracking.EyeGaze; using EyeTracking.MarrowSDK; using HarmonyLib; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppInterop.Runtime.InteropTypes.Fields; using Il2CppRealisticEyeMovements; using Il2CppSLZ.Marrow; using Il2CppSLZ.VRMK; using Il2CppSystem.Collections.Generic; using MelonLoader; using MelonLoader.Preferences; using Microsoft.CodeAnalysis; using MiniNtp; using OscCore; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using Unity.IL2CPP.CompilerServices.BlobHandles; using UnityEngine; using UnityEngine.Events; using UnityEngine.Profiling; using UnityEngine.XR; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(Core), "EyeTracking", "1.0.1", "Checkerboard", null)] [assembly: MelonGame("Stress Level Zero", "BONELAB")] [assembly: MelonOptionalDependencies(new string[] { "LabFusion" })] [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: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.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 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 Unity.IL2CPP.CompilerServices.BlobHandles { public enum Option { NullChecks = 1, ArrayBoundsChecks, DivideByZeroChecks } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] public class Il2CppSetOptionAttribute : Attribute { public Option Option { get; private set; } public object Value { get; private set; } public Il2CppSetOptionAttribute(Option option, object value) { Option = option; Value = value; } } } 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); } [Il2CppSetOption(Option.NullChecks, false)] 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); } } [Il2CppSetOption(Option.NullChecks, false)] public void Add(BlobString blobStr, T value) { HandleToValue.Add(blobStr.Handle, value); } [Il2CppSetOption(Option.NullChecks, false)] 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; } [Il2CppSetOption(Option.NullChecks, false)] public bool Remove(BlobString blobStr) { return HandleToValue.Remove(blobStr.Handle); } [MethodImpl(MethodImplOptions.AggressiveInlining)] [Il2CppSetOption(Option.NullChecks, false)] 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; } = System.Text.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 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 (Exception) { 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; } } } public class PropertyOutput : MonoBehaviour { private OscSender m_Sender; private string m_Address = ""; private GameObject m_Object; private Component m_SourceComponent; private bool m_MemberIsProperty; private string m_PropertyName; private string m_PropertyTypeName; private Vector2ElementFilter m_SendVector2Elements; private Vector3ElementFilter m_SendVector3Elements; private bool m_PreviousBooleanValue; private int m_PreviousIntValue; private long m_PreviousLongValue; private double m_PreviousDoubleValue; private float m_PreviousSingleValue; private string m_PreviousStringValue; private Color m_PreviousColorValue; private Vector2 m_PreviousVec2Value; private Vector3 m_PreviousVec3Value; private bool m_HasSender; private MemberInfo m_MemberInfo; private PropertyInfo m_Property; private FieldInfo m_Field; public OscSender Sender { get { return m_Sender; } set { m_Sender = ((value == null) ? m_Sender : value); } } public Component SourceComponent { get { return m_SourceComponent; } set { m_SourceComponent = (((Object)(object)value == (Object)null) ? m_SourceComponent : value); } } public PropertyInfo Property { get { return m_Property; } set { m_MemberInfo = value; m_Property = value; m_Field = null; m_MemberIsProperty = true; } } public FieldInfo Field { get { return m_Field; } set { m_MemberInfo = value; m_Field = value; m_Property = null; m_MemberIsProperty = false; } } private void OnEnable() { if ((Object)(object)m_Object == (Object)null) { m_Object = ((Component)this).gameObject; } m_HasSender = m_Sender != null; SetPropertyFromSerialized(); } private void OnValidate() { Utils.ValidateAddress(ref m_Address); if (m_Sender == null) { m_Sender = ((Component)this).gameObject.GetComponentInParent<OscSender>(); } m_HasSender = m_Sender != null; } private void Update() { //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) //IL_0321: Unknown result type (might be due to invalid IL or missing references) //IL_0326: Unknown result type (might be due to invalid IL or missing references) if (m_MemberInfo == null || !m_HasSender || m_Sender.Client == null) { return; } object obj = (m_MemberIsProperty ? m_Property.GetValue(m_SourceComponent) : m_Field.GetValue(m_SourceComponent)); if (obj == null) { return; } string propertyTypeName = m_PropertyTypeName; if (propertyTypeName == null) { return; } int castValue5; switch (propertyTypeName.Length) { case 5: { char c = propertyTypeName[3]; if ((uint)c <= 51u) { switch (c) { default: return; case '1': if (!(propertyTypeName == "Int16")) { return; } break; case '3': if (!(propertyTypeName == "Int32")) { return; } break; } } else { if (c == '6') { if (propertyTypeName == "Int64" && ValueChanged(ref m_PreviousLongValue, obj, out var castValue6)) { m_Sender.Client.Send(m_Address, castValue6); } break; } if (c == 'o') { if (!(propertyTypeName == "Color")) { break; } goto IL_02f0; } if (c != 't' || !(propertyTypeName == "SByte")) { break; } } goto IL_0217; } case 6: switch (propertyTypeName[1]) { default: return; case 'I': break; case 'i': { if (propertyTypeName == "Single" && ValueChanged(ref m_PreviousSingleValue, obj, out var castValue4)) { m_Sender.Client.Send(m_Address, castValue4); } return; } case 'o': { if (propertyTypeName == "Double" && ValueChanged(ref m_PreviousDoubleValue, obj, out var castValue3)) { m_Sender.Client.Send(m_Address, castValue3); } return; } case 't': { if (propertyTypeName == "String" && ValueChanged(ref m_PreviousStringValue, obj, out var castValue2)) { m_Sender.Client.Send(m_Address, castValue2); } return; } } if (!(propertyTypeName == "UInt16")) { break; } goto IL_0217; case 7: switch (propertyTypeName[0]) { default: return; case 'C': break; case 'V': if (!(propertyTypeName == "Vector2")) { if (propertyTypeName == "Vector3") { SendVector3(obj); } } else { SendVector2(obj); } return; case 'B': { if (propertyTypeName == "Boolean" && ValueChanged(ref m_PreviousBooleanValue, obj, out var castValue)) { m_Sender.Client.Send(m_Address, castValue); } return; } } if (!(propertyTypeName == "Color32")) { break; } goto IL_02f0; case 4: { if (!(propertyTypeName == "Byte")) { break; } goto IL_0217; } IL_02f0: if (!((Color)(ref m_PreviousColorValue)).Equals((Color)obj)) { m_PreviousColorValue = (Color)obj; m_Sender.Client.Send(m_Address, Color32.op_Implicit(m_PreviousColorValue)); } break; IL_0217: if (ValueChanged(ref m_PreviousIntValue, obj, out castValue5)) { m_Sender.Client.Send(m_Address, castValue5); } break; } } private void SendVector2(object obj) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) Vector2 val = (Vector2)obj; switch (m_SendVector2Elements) { case Vector2ElementFilter.XY: if (!((Vector2)(ref m_PreviousVec2Value)).Equals(val)) { m_PreviousVec2Value = val; m_Sender.Client.Send(m_Address, val); } break; case Vector2ElementFilter.X: if (!m_PreviousSingleValue.Equals(val.x)) { m_PreviousSingleValue = val.x; m_Sender.Client.Send(m_Address, val.x); } break; case Vector2ElementFilter.Y: if (!m_PreviousSingleValue.Equals(val.y)) { m_PreviousSingleValue = val.y; m_Sender.Client.Send(m_Address, val.y); } break; } } private void SendVector3(object value) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: 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) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) Vector3 val = (Vector3)value; switch (m_SendVector3Elements) { case Vector3ElementFilter.XYZ: if (!((Vector3)(ref m_PreviousVec3Value)).Equals(val)) { m_PreviousVec3Value = val; m_Sender.Client.Send(m_Address, val); } break; case Vector3ElementFilter.X: if (!m_PreviousSingleValue.Equals(val.x)) { m_PreviousSingleValue = val.x; m_Sender.Client.Send(m_Address, val.x); } break; case Vector3ElementFilter.Y: if (!m_PreviousSingleValue.Equals(val.y)) { m_PreviousSingleValue = val.y; m_Sender.Client.Send(m_Address, val.y); } break; case Vector3ElementFilter.Z: if (!m_PreviousSingleValue.Equals(val.z)) { m_PreviousSingleValue = val.z; m_Sender.Client.Send(m_Address, val.z); } break; case Vector3ElementFilter.XY: { Vector2 val4 = default(Vector2); ((Vector2)(ref val4))..ctor(val.x, val.y); if (!((Vector2)(ref m_PreviousVec2Value)).Equals(val4)) { m_PreviousVec2Value = val4; m_Sender.Client.Send(m_Address, val4); } break; } case Vector3ElementFilter.XZ: { Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(val.x, val.z); if (!((Vector2)(ref m_PreviousVec2Value)).Equals(val3)) { m_PreviousVec2Value = val3; m_Sender.Client.Send(m_Address, val3); } break; } case Vector3ElementFilter.YZ: { Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(val.y, val.z); if (!((Vector2)(ref m_PreviousVec2Value)).Equals(val2)) { m_PreviousVec2Value = val2; m_Sender.Client.Send(m_Address, val2); } break; } } } private static bool ValueChanged<T>(ref T previousValue, object value, out T castValue) where T : IEquatable<T> { castValue = (T)value; if (!castValue.Equals(previousValue)) { previousValue = castValue; return true; } return false; } internal Component[] GetObjectComponents() { return Il2CppArrayBase<Component>.op_Implicit(((Object)(object)m_Object == (Object)null) ? null : m_Object.GetComponents<Component>()); } internal void SetPropertyFromSerialized() { if (!((Object)(object)m_SourceComponent == (Object)null)) { Type type = ((object)m_SourceComponent).GetType(); if (m_MemberIsProperty) { Property = type.GetProperty(m_PropertyName); } else { Field = type.GetField(m_PropertyName); } } } } [Serializable] public class BoolUnityEvent : UnityEvent<bool> { } [Serializable] public class IntUnityEvent : UnityEvent<int> { } [Serializable] public class LongUnityEvent : UnityEvent<long> { } [Serializable] public class FloatUnityEvent : UnityEvent<float> { } [Serializable] public class DoubleUnityEvent : UnityEvent<double> { } [Serializable] public class StringUnityEvent : UnityEvent<string> { } [Serializable] public class ColorUnityEvent : UnityEvent<Color> { } [Serializable] public class Vector3UnityEvent : UnityEvent<Vector3> { } [Serializable] public class BlobUnityEvent : UnityEvent<byte[], int> { } 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 OscServer value)) { value = new OscServer(port); PortToServer[port] = value; } return value; } public static bool Remove(int port) { if (PortToServer.TryGetValue(port, out OscServer 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 OscActionPair 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 OscActionPair 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 OscActionPair 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 string value)) { value = Encoding.ASCII.GetString(bufferPtr, addressLength); m_ByteLengthToStringBuffer[addressLength] = value; } else { OverwriteAsciiString(value, bufferPtr); } if (!AddressSpace.TryMatchPatternHandler(value, m_PatternMatchedMethods)) { return; } string address = string.Copy(value); AddressSpace.AddressToMethod.Add(address, 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); } [Il2CppSetOption(Option.NullChecks, false)] 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; } } [Il2CppSetOption(Option.NullChecks, false)] public void Add(string address, Action<OscMessageValues> callback) { Add(address, new OscActionPair(callback)); } [Il2CppSetOption(Option.NullChecks, false)] 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); } [Il2CppSetOption(Option.NullChecks, false)] public bool Remove(string address, OscActionPair callbacks) { if (!SourceToBlob.TryGetValue(address, out var value)) { return false; } if (!HandleToValue.TryGetValue(value.Handle, out OscActionPair 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)] [Il2CppSetOption(Option.NullChecks, false)] 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) { OscMessageValues values2 = values; k_Builder.Clear(); k_Builder.Append(address.ToString()); k_Builder.Append(" ,"); values2.ForEachElement(delegate(int i, TypeTag type) { k_Builder.Append((char)type); }); k_Builder.Append(" "); int lastIndex = values2.ElementCount - 1; values2.ForEachElement(delegate(int i, TypeTag type) { string value = values2.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 EyeTracking { public class Core : MelonMod { public static bool HasFusion; internal static Core Instance { get; private set; } internal static MelonPreferences_Category Category { get; private set; } internal static MelonPreferences_Entry<bool> EnableEyeTracking { get; set; } internal static MelonPreferences_Entry<string> ActiveEyeGazeImplementation { get; private set; } public static Page RootPage { get; private set; } private static BoolElement EnableDebug { get; set; } public static Page ImplementationsPage { get; private set; } public override void OnInitializeMelon() { //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) Instance = this; Category = MelonPreferences.CreateCategory("EyeTracking", "Eye Tracking Settings"); EnableEyeTracking = Category.CreateEntry<bool>("EnableEyeTracking", true, "Enable Eye Tracking", (string)null, false, false, (ValueValidator)null, (string)null); ActiveEyeGazeImplementation = Category.CreateEntry<string>("ActiveEyeGazeImplementation", "OSC", "Active Eye Gaze Implementation", (string)null, false, false, (ValueValidator)null, (string)null); Category.SaveToFile(false); HasFusion = MelonBase.FindMelon("LabFusion", "Lakatrazz") != null; if (HasFusion) { Utils.LoadAssemblyFromAssembly(((MelonBase)Instance).MelonAssembly.Assembly, "EyeTracking.Resources.EyeTrackingFusion.dll").GetType("EyeTracking.Fusion.ModuleLoader").GetMethod("LoadModule") .Invoke(null, null); } RootPage = Page.Root.CreatePage("Eye Tracking", Color.green, 0, true); RootPage.CreateFunction("Current Implementation: " + ActiveEyeGazeImplementation.Value, Color.green, (Action)delegate { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown Notifier.Send(new Notification { ShowTitleOnPopup = true, Title = NotificationText.op_Implicit("hi"), Message = NotificationText.op_Implicit("oh, hello there"), Type = (NotificationType)0 }); }); ImplementationsPage = RootPage.CreatePage("Available Implementations", Color.cyan, 0, true); ImplementationManager.Initialize(); Hooking.OnSwitchAvatarPostfix += EyeSolver.OnAvatarSwap; } public override void OnUpdate() { if (EnableEyeTracking.Value && ImplementationManager.CurrentImplementation != null) { ImplementationManager.CurrentImplementation.Update(); EyeSolver.UpdateBlink(); } } public override void OnGUI() { if (EnableDebug != null && EnableDebug.Value && ImplementationManager.CurrentImplementation != null) { EyeGazeDebugOverlay.Draw(); } } } public static class EyeSolver { public static readonly float SmoothingSpeed = 35f; private static float _currentLeftBlink = 0f; private static float _currentRightBlink = 0f; internal static AvatarEyeGazeDescriptor CurrentEyeGazeDescriptor { get; private set; } internal static int LeftBlinkIndex { get; private set; } = -1; internal static int RightBlinkIndex { get; private set; } = -1; public static void OnAvatarSwap(Avatar avatar) { if (!((Object)(object)avatar == (Object)null) && !((Object)(object)((Component)((Component)avatar).transform.parent).GetComponent<RigManager>() != (Object)(object)Player.RigManager)) { CurrentEyeGazeDescriptor = null; LeftBlinkIndex = -1; RightBlinkIndex = -1; CurrentEyeGazeDescriptor = ((Component)avatar).GetComponent<AvatarEyeGazeDescriptor>(); if (!((Object)(object)CurrentEyeGazeDescriptor == (Object)null)) { LeftBlinkIndex = CurrentEyeGazeDescriptor.LeftEyeBlinkShapeKey.Get(); RightBlinkIndex = CurrentEyeGazeDescriptor.RightEyeBlinkShapeKey.Get(); } } } public static void UpdateBlink() { if (!Core.EnableEyeTracking.Value || !ImplementationManager.CurrentImplementation.IsLoaded || (Object)(object)CurrentEyeGazeDescriptor == (Object)null || (Object)(object)CurrentEyeGazeDescriptor.SkinnedMeshRenderer.Get() == (Object)null || LeftBlinkIndex == -1 || RightBlinkIndex == -1) { return; } float num = 1f - Tracking.Data.Eye.Left.Openness; float num2 = 1f - Tracking.Data.Eye.Right.Openness; _currentLeftBlink = Mathf.Lerp(_currentLeftBlink, num, SmoothingSpeed * Time.deltaTime); _currentRightBlink = Mathf.Lerp(_currentRightBlink, num2, SmoothingSpeed * Time.deltaTime); AvatarEyeGazeDescriptor currentEyeGazeDescriptor = CurrentEyeGazeDescriptor; if (currentEyeGazeDescriptor != null) { Il2CppReferenceField<SkinnedMeshRenderer> skinnedMeshRenderer = currentEyeGazeDescriptor.SkinnedMeshRenderer; if (skinnedMeshRenderer != null) { SkinnedMeshRenderer obj = skinnedMeshRenderer.Get(); if (obj != null) { obj.SetBlendShapeWeight(LeftBlinkIndex, _currentLeftBlink * 100f); } } } AvatarEyeGazeDescriptor currentEyeGazeDescriptor2 = CurrentEyeGazeDescriptor; if (currentEyeGazeDescriptor2 == null) { return; } Il2CppReferenceField<SkinnedMeshRenderer> skinnedMeshRenderer2 = currentEyeGazeDescriptor2.SkinnedMeshRenderer; if (skinnedMeshRenderer2 != null) { SkinnedMeshRenderer obj2 = skinnedMeshRenderer2.Get(); if (obj2 != null) { obj2.SetBlendShapeWeight(RightBlinkIndex, _currentRightBlink * 100f); } } } } public static class Tracking { public static readonly TrackingData Data = new TrackingData(); } public static class ImplementationManager { private static readonly List<EyeGazeImplementation> Implementations = new List<EyeGazeImplementation>(); public static EyeGazeImplementation? CurrentImplementation { get; private set; } internal static void Initialize() { //IL_0060: Unknown result type (might be due to invalid IL or missing references) LoadImplementations(); if (CurrentImplementation == null) { Core.ActiveEyeGazeImplementation.Value = Core.ActiveEyeGazeImplementation.DefaultValue; Core.Category.SaveToFile(false); LoadImplementations(); } foreach (EyeGazeImplementation implementation in Implementations) { Core.ImplementationsPage.CreateFunction(implementation.Name, Color.white, (Action)delegate { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown Core.ActiveEyeGazeImplementation.Value = implementation.Name; Core.Category.SaveToFile(false); Notifier.Send(new Notification { ShowTitleOnPopup = true, Title = NotificationText.op_Implicit("Eye Tracking Implementation Changed"), Message = NotificationText.op_Implicit("Please restart the game for this change to take affect."), Type = (NotificationType)3 }); }); } } private static void LoadImplementations() { Implementations.Clear(); CurrentImplementation = null; foreach (MelonBase registeredMelo