Decompiled source of EyeTracking v1.1.1

Mods/EyeTracking.dll

Decompiled 2 days ago
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);