Decompiled source of OpenTrack Compatible Head Tracking for PEAK v1.0.2

plugins\CameraUnlock.Core.dll

Decompiled 2 weeks 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.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using CameraUnlock.Core.Aim;
using CameraUnlock.Core.Config;
using CameraUnlock.Core.Data;
using CameraUnlock.Core.Math;
using CameraUnlock.Core.Processing;
using CameraUnlock.Core.Processing.AxisTransform;
using CameraUnlock.Core.Protocol;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("CameraUnlock Mods")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Core shared library for CameraUnlock head tracking mods")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+ffa50e702c2238550a17fde0fc8b3e63da95026c")]
[assembly: AssemblyProduct("CameraUnlock.Core")]
[assembly: AssemblyTitle("CameraUnlock.Core")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace CameraUnlock.Core.Tracking
{
	public static class StaticHeadTrackingCore
	{
		private static OpenTrackReceiver _receiver;

		private static TrackingProcessor _processor;

		private static IHeadTrackingConfig _config;

		private static bool _initialized;

		private static bool _enabled = true;

		private static bool _hasAutoRecentered;

		private static Action<string> _log;

		public static bool IsEnabled
		{
			get
			{
				return _enabled;
			}
			set
			{
				if (_enabled != value)
				{
					_enabled = value;
					_log?.Invoke(_enabled ? "Tracking enabled" : "Tracking disabled");
					if (!_enabled)
					{
						Reset();
					}
				}
			}
		}

		public static bool IsReceiving
		{
			get
			{
				if (_receiver != null)
				{
					return _receiver.IsReceiving;
				}
				return false;
			}
		}

		public static bool IsRemoteConnection
		{
			get
			{
				if (_receiver != null)
				{
					return _receiver.IsRemoteConnection;
				}
				return false;
			}
		}

		public static bool IsInitialized => _initialized;

		public static IHeadTrackingConfig Config => _config;

		public static TrackingProcessor Processor => _processor;

		public static OpenTrackReceiver Receiver => _receiver;

		public static void Initialize(IHeadTrackingConfig config, Action<string> log = null)
		{
			if (_initialized)
			{
				log?.Invoke("StaticHeadTrackingCore already initialized");
				return;
			}
			_config = config;
			_log = log;
			_initialized = true;
			_log?.Invoke("StaticHeadTrackingCore initializing...");
			_processor = new TrackingProcessor
			{
				Sensitivity = config.Sensitivity,
				SmoothingFactor = 0f
			};
			_receiver = new OpenTrackReceiver();
			_receiver.Log = _log;
			if (_receiver.Start(config.UdpPort))
			{
				_log?.Invoke($"Listening on UDP port {config.UdpPort}");
			}
			_enabled = config.EnableOnStartup;
		}

		public static bool Update(float deltaTime)
		{
			if (!_initialized || !_enabled || _receiver == null || _processor == null)
			{
				return false;
			}
			if (!_receiver.IsReceiving)
			{
				return false;
			}
			if (!_hasAutoRecentered)
			{
				_hasAutoRecentered = true;
				_receiver.Recenter();
				_log?.Invoke("Auto-recentered on first connection");
			}
			return true;
		}

		public static TrackingPose GetProcessedPose(float deltaTime)
		{
			if (!_initialized || _receiver == null || _processor == null)
			{
				return new TrackingPose(0f, 0f, 0f, 0L);
			}
			TrackingPose latestPose = _receiver.GetLatestPose();
			return _processor.Process(latestPose, deltaTime);
		}

		public static void GetProcessedRotation(float deltaTime, out float yaw, out float pitch, out float roll)
		{
			TrackingPose processedPose = GetProcessedPose(deltaTime);
			yaw = processedPose.Yaw;
			pitch = processedPose.Pitch;
			roll = processedPose.Roll;
		}

		public static void GetAimScreenOffset(float yaw, float pitch, float roll, float horizontalFov, float verticalFov, float screenWidth, float screenHeight, out float offsetX, out float offsetY)
		{
			ScreenOffsetCalculator.Calculate(yaw, pitch, roll, horizontalFov, verticalFov, screenWidth, screenHeight, 1f, out offsetX, out offsetY);
		}

		public static void GetAimScreenPosition(float yaw, float pitch, float roll, float horizontalFov, float verticalFov, float screenWidth, float screenHeight, out float posX, out float posY)
		{
			GetAimScreenOffset(yaw, pitch, roll, horizontalFov, verticalFov, screenWidth, screenHeight, out var offsetX, out var offsetY);
			posX = screenWidth * 0.5f + offsetX;
			posY = screenHeight * 0.5f + offsetY;
		}

		public static void Recenter()
		{
			_receiver?.Recenter();
			_processor?.Reset();
			_log?.Invoke("Recentered");
		}

		public static bool Toggle()
		{
			IsEnabled = !IsEnabled;
			return IsEnabled;
		}

		public static void Reset()
		{
			_processor?.Reset();
			_hasAutoRecentered = false;
		}

		public static void Shutdown()
		{
			if (_receiver != null)
			{
				_receiver.Stop();
				_receiver = null;
			}
			_processor = null;
			_config = null;
			_initialized = false;
			_hasAutoRecentered = false;
			_log?.Invoke("StaticHeadTrackingCore shut down");
			_log = null;
		}
	}
}
namespace CameraUnlock.Core.State
{
	public static class CommonMenuScenes
	{
		public static string[] Default { get; } = new string[22]
		{
			"MainMenu", "Menu", "Main Menu", "StartMenu", "Start Menu", "TitleScreen", "Title", "Credits", "Loading", "LoadingScreen",
			"Splash", "Intro", "Cutscene", "Options", "Settings", "Pause", "PauseMenu", "GameOver", "Game Over", "EndGame",
			"Victory", "Defeat"
		};


		public static HashSet<string> CreateDefaultSet()
		{
			return new HashSet<string>(Default, StringComparer.OrdinalIgnoreCase);
		}
	}
	public enum GameContext
	{
		Unknown,
		Menu,
		Loading,
		Gameplay,
		Cutscene
	}
	public abstract class GameStateDetectorBase : IGameStateDetector, IDisposable
	{
		public const float DefaultCheckIntervalSeconds = 0.1f;

		private readonly float _checkIntervalSeconds;

		private readonly GetCurrentTime _getTime;

		private readonly HashSet<string> _menuSceneNames;

		private bool _cachedIsInGameplay;

		private float _lastCheckTime;

		private bool _disposed;

		private string _cachedSceneName;

		private bool _cachedIsMenuScene;

		public bool IsInGameplay
		{
			get
			{
				if (_disposed)
				{
					return false;
				}
				float num = _getTime();
				if (num - _lastCheckTime < _checkIntervalSeconds)
				{
					return _cachedIsInGameplay;
				}
				_lastCheckTime = num;
				_cachedIsInGameplay = CheckGameplayState();
				return _cachedIsInGameplay;
			}
		}

		protected GameStateDetectorBase(GetCurrentTime getTime, float checkIntervalSeconds = 0.1f)
		{
			_getTime = getTime ?? throw new ArgumentNullException("getTime");
			_checkIntervalSeconds = checkIntervalSeconds;
			_menuSceneNames = CommonMenuScenes.CreateDefaultSet();
			_cachedSceneName = string.Empty;
		}

		public void InvalidateCache()
		{
			_lastCheckTime = 0f;
		}

		protected virtual bool CheckGameplayState()
		{
			string currentSceneName = GetCurrentSceneName();
			if (!string.Equals(_cachedSceneName, currentSceneName, StringComparison.Ordinal))
			{
				_cachedSceneName = currentSceneName ?? string.Empty;
				_cachedIsMenuScene = !string.IsNullOrEmpty(_cachedSceneName) && _menuSceneNames.Contains(_cachedSceneName);
			}
			if (_cachedIsMenuScene)
			{
				return false;
			}
			if (IsGamePaused())
			{
				return false;
			}
			if (IsCursorVisible())
			{
				return false;
			}
			if (IsMenuVisible())
			{
				return false;
			}
			if (IsInventoryOpen())
			{
				return false;
			}
			if (IsTextInputActive())
			{
				return false;
			}
			if (IsPlayerDead())
			{
				return false;
			}
			if (!HasCameraControl())
			{
				return false;
			}
			return true;
		}

		protected abstract string GetCurrentSceneName();

		protected virtual bool IsGamePaused()
		{
			return false;
		}

		protected virtual bool IsCursorVisible()
		{
			return false;
		}

		protected virtual bool IsMenuVisible()
		{
			return false;
		}

		protected virtual bool IsInventoryOpen()
		{
			return false;
		}

		protected virtual bool IsTextInputActive()
		{
			return false;
		}

		protected virtual bool IsPlayerDead()
		{
			return false;
		}

		protected virtual bool HasCameraControl()
		{
			return true;
		}

		public void AddMenuScene(string sceneName)
		{
			if (string.IsNullOrEmpty(sceneName))
			{
				throw new ArgumentException("Scene name cannot be null or empty", "sceneName");
			}
			_menuSceneNames.Add(sceneName);
			if (string.Equals(_cachedSceneName, sceneName, StringComparison.OrdinalIgnoreCase))
			{
				_cachedIsMenuScene = true;
			}
		}

		public bool RemoveMenuScene(string sceneName)
		{
			if (string.IsNullOrEmpty(sceneName))
			{
				throw new ArgumentException("Scene name cannot be null or empty", "sceneName");
			}
			bool num = _menuSceneNames.Remove(sceneName);
			if (num && string.Equals(_cachedSceneName, sceneName, StringComparison.OrdinalIgnoreCase))
			{
				_cachedIsMenuScene = false;
			}
			return num;
		}

		public void ClearMenuScenes()
		{
			_menuSceneNames.Clear();
			_cachedIsMenuScene = false;
		}

		public void Dispose()
		{
			if (!_disposed)
			{
				_disposed = true;
				OnDispose();
			}
		}

		protected virtual void OnDispose()
		{
		}
	}
	public interface IGameStateDetector : IDisposable
	{
		bool IsInGameplay { get; }

		void InvalidateCache();
	}
	public delegate bool GameplayConditionCheck();
	public delegate float GetCurrentTime();
	public static class TrackingState
	{
		private static int _enabledState;

		public static bool IsEnabled => Interlocked.CompareExchange(ref _enabledState, 0, 0) == 1;

		public static event Action<bool> OnStateChanged;

		public static void Initialize(bool enabled)
		{
			Interlocked.Exchange(ref _enabledState, enabled ? 1 : 0);
		}

		public static bool Toggle()
		{
			int num;
			int num2;
			do
			{
				num = Interlocked.CompareExchange(ref _enabledState, 0, 0);
				num2 = ((num == 0) ? 1 : 0);
			}
			while (Interlocked.CompareExchange(ref _enabledState, num2, num) != num);
			bool flag = num2 == 1;
			TrackingState.OnStateChanged?.Invoke(flag);
			return flag;
		}

		public static void Enable()
		{
			if (Interlocked.Exchange(ref _enabledState, 1) == 0)
			{
				TrackingState.OnStateChanged?.Invoke(obj: true);
			}
		}

		public static void Disable()
		{
			if (Interlocked.Exchange(ref _enabledState, 0) == 1)
			{
				TrackingState.OnStateChanged?.Invoke(obj: false);
			}
		}

		public static void SetEnabled(bool enabled)
		{
			if (enabled)
			{
				Enable();
			}
			else
			{
				Disable();
			}
		}
	}
}
namespace CameraUnlock.Core.Protocol
{
	public interface ITrackingDataSource
	{
		bool IsReceiving { get; }

		bool IsRemoteConnection { get; }

		bool IsFailed { get; }

		TrackingPose GetLatestPose();

		void GetRawRotation(out float yaw, out float pitch, out float roll);

		void Recenter();
	}
	public static class OpenTrackPacket
	{
		public const int MinPacketSize = 48;

		public const int XOffset = 0;

		public const int YOffset = 8;

		public const int ZOffset = 16;

		public const int YawOffset = 24;

		public const int PitchOffset = 32;

		public const int RollOffset = 40;

		public const float CmToMeters = 0.01f;

		public static bool TryParse(byte[] data, out TrackingPose pose)
		{
			pose = default(TrackingPose);
			if (data == null || data.Length < 48)
			{
				return false;
			}
			double num = BitConverter.ToDouble(data, 24);
			double num2 = BitConverter.ToDouble(data, 32);
			double num3 = BitConverter.ToDouble(data, 40);
			if (double.IsNaN(num) || double.IsInfinity(num) || double.IsNaN(num2) || double.IsInfinity(num2) || double.IsNaN(num3) || double.IsInfinity(num3))
			{
				return false;
			}
			pose = new TrackingPose((float)num, (float)num2, (float)num3);
			return true;
		}

		public static bool TryParsePosition(byte[] data, out PositionData position)
		{
			position = default(PositionData);
			if (data == null || data.Length < 48)
			{
				return false;
			}
			double num = BitConverter.ToDouble(data, 0);
			double num2 = BitConverter.ToDouble(data, 8);
			double num3 = BitConverter.ToDouble(data, 16);
			if (double.IsNaN(num) || double.IsInfinity(num) || double.IsNaN(num2) || double.IsInfinity(num2) || double.IsNaN(num3) || double.IsInfinity(num3))
			{
				return false;
			}
			position = new PositionData((float)num * 0.01f, (float)num2 * 0.01f, (float)num3 * 0.01f);
			return true;
		}
	}
	public sealed class OpenTrackReceiver : ITrackingDataSource, IDisposable
	{
		public const int DefaultPort = 4242;

		private const int ReceiveTimeoutMs = 100;

		private const int DisconnectThreshold = 50;

		private const int RetryIntervalMs = 5000;

		private const int RetryLogIntervalMs = 30000;

		public const int DefaultMaxDataAgeMs = 500;

		private UdpClient _udpClient;

		private Thread _receiveThread;

		private volatile bool _isRunning;

		private volatile bool _isConnected;

		private int _consecutiveTimeouts;

		private bool _disposed;

		private volatile bool _retrying;

		private Thread _retryThread;

		private int _port;

		private volatile float _rotationPitch;

		private volatile float _rotationYaw;

		private volatile float _rotationRoll;

		private long _timestampTicks;

		private volatile bool _isRemoteConnection;

		private volatile float _positionX;

		private volatile float _positionY;

		private volatile float _positionZ;

		private float _offsetYaw;

		private float _offsetPitch;

		private float _offsetRoll;

		private float _offsetX;

		private float _offsetY;

		private float _offsetZ;

		private readonly object _offsetLock = new object();

		private readonly CoordinateTransformer _transformer;

		public bool HasTransformer => _transformer != null;

		public bool IsReceiving => _isConnected;

		public bool IsFailed { get; private set; }

		public bool IsRemoteConnection => _isRemoteConnection;

		public Action<string> Log { get; set; }

		public OpenTrackReceiver()
			: this(null)
		{
		}

		public OpenTrackReceiver(CoordinateTransformer transformer)
		{
			_transformer = transformer;
		}

		public bool Start(int port = 4242)
		{
			if (_disposed)
			{
				return false;
			}
			if (_isRunning)
			{
				return true;
			}
			if (_retrying)
			{
				return false;
			}
			IsFailed = false;
			_port = port;
			try
			{
				_udpClient = new UdpClient(new IPEndPoint(IPAddress.Any, port));
				_udpClient.Client.ReceiveTimeout = 100;
			}
			catch (SocketException)
			{
				IsFailed = true;
				Log?.Invoke($"Failed to bind UDP port {port} -- will retry every {5}s");
				StartRetryLoop();
				return false;
			}
			_isRunning = true;
			_receiveThread = new Thread(ReceiveLoop)
			{
				Name = "CameraUnlock-OpenTrackReceiver",
				IsBackground = true
			};
			_receiveThread.Start();
			return true;
		}

		private void StartRetryLoop()
		{
			_retrying = true;
			_retryThread = new Thread(RetryLoop)
			{
				Name = "CameraUnlock-PortRetry",
				IsBackground = true
			};
			_retryThread.Start();
		}

		private void RetryLoop()
		{
			int num = 6;
			int num2 = 0;
			while (_retrying && !_disposed)
			{
				for (int i = 0; i < 50; i++)
				{
					if (!_retrying || _disposed)
					{
						return;
					}
					Thread.Sleep(100);
				}
				if (!_retrying || _disposed)
				{
					break;
				}
				num2++;
				try
				{
					UdpClient udpClient = new UdpClient(new IPEndPoint(IPAddress.Any, _port));
					udpClient.Client.ReceiveTimeout = 100;
					if (!_retrying || _disposed)
					{
						try
						{
							udpClient.Close();
							break;
						}
						catch (SocketException)
						{
							break;
						}
					}
					_udpClient = udpClient;
					IsFailed = false;
					_retrying = false;
					_isRunning = true;
					_receiveThread = new Thread(ReceiveLoop)
					{
						Name = "CameraUnlock-OpenTrackReceiver",
						IsBackground = true
					};
					_receiveThread.Start();
					Log?.Invoke($"Bound UDP port {_port} after {num2} retries");
					break;
				}
				catch (SocketException)
				{
					if (num2 % num == 0)
					{
						Log?.Invoke($"Still waiting for UDP port {_port} ({num2 * 5000 / 1000}s elapsed)");
					}
				}
			}
		}

		public void Stop()
		{
			_isRunning = false;
			_retrying = false;
			Thread retryThread = _retryThread;
			_retryThread = null;
			retryThread?.Join(1000);
			Thread receiveThread = _receiveThread;
			_receiveThread = null;
			receiveThread?.Join(1000);
			UdpClient udpClient = _udpClient;
			_udpClient = null;
			if (udpClient != null)
			{
				try
				{
					udpClient.Close();
				}
				catch (SocketException)
				{
				}
			}
			_isConnected = false;
		}

		public TrackingPose GetRawPose()
		{
			float rotationYaw = _rotationYaw;
			float rotationPitch = _rotationPitch;
			float rotationRoll = _rotationRoll;
			long timestampTicks = Interlocked.Read(ref _timestampTicks);
			return new TrackingPose(rotationYaw, rotationPitch, rotationRoll, timestampTicks);
		}

		public void GetRawRotation(out float yaw, out float pitch, out float roll)
		{
			pitch = _rotationPitch;
			yaw = _rotationYaw;
			roll = _rotationRoll;
		}

		public TrackingPose GetLatestPose()
		{
			float num = _rotationYaw;
			float num2 = _rotationPitch;
			float num3 = _rotationRoll;
			long timestampTicks = Interlocked.Read(ref _timestampTicks);
			Monitor.Enter(_offsetLock);
			try
			{
				num -= _offsetYaw;
				num2 -= _offsetPitch;
				num3 -= _offsetRoll;
			}
			finally
			{
				Monitor.Exit(_offsetLock);
			}
			return new TrackingPose(num, num2, num3, timestampTicks);
		}

		public TrackingPose GetLatestPoseTransformed()
		{
			TrackingPose trackingPose = GetLatestPose();
			if (_transformer != null)
			{
				trackingPose = _transformer.Transform(trackingPose);
			}
			return trackingPose;
		}

		public PositionData GetLatestPosition()
		{
			float num = _positionX;
			float num2 = _positionY;
			float num3 = _positionZ;
			long timestampTicks = Interlocked.Read(ref _timestampTicks);
			Monitor.Enter(_offsetLock);
			try
			{
				num -= _offsetX;
				num2 -= _offsetY;
				num3 -= _offsetZ;
			}
			finally
			{
				Monitor.Exit(_offsetLock);
			}
			return new PositionData(num, num2, num3, timestampTicks);
		}

		public bool IsDataFresh(int maxAgeMs = 500)
		{
			long num = Interlocked.Read(ref _timestampTicks);
			if (num == 0L)
			{
				return false;
			}
			return (double)(Stopwatch.GetTimestamp() - num) * 1000.0 / (double)Stopwatch.Frequency < (double)maxAgeMs;
		}

		public void Recenter()
		{
			Monitor.Enter(_offsetLock);
			try
			{
				_offsetYaw = _rotationYaw;
				_offsetPitch = _rotationPitch;
				_offsetRoll = _rotationRoll;
				_offsetX = _positionX;
				_offsetY = _positionY;
				_offsetZ = _positionZ;
			}
			finally
			{
				Monitor.Exit(_offsetLock);
			}
		}

		public void ResetOffset()
		{
			Monitor.Enter(_offsetLock);
			try
			{
				_offsetYaw = 0f;
				_offsetPitch = 0f;
				_offsetRoll = 0f;
				_offsetX = 0f;
				_offsetY = 0f;
				_offsetZ = 0f;
			}
			finally
			{
				Monitor.Exit(_offsetLock);
			}
		}

		private void ReceiveLoop()
		{
			IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
			while (_isRunning)
			{
				try
				{
					if (_udpClient == null)
					{
						break;
					}
					byte[] array = _udpClient.Receive(ref remoteEP);
					if (array.Length >= 48)
					{
						if (OpenTrackPacket.TryParse(array, out var pose))
						{
							_rotationYaw = pose.Yaw;
							_rotationPitch = pose.Pitch;
							_rotationRoll = pose.Roll;
							Interlocked.Exchange(ref _timestampTicks, Stopwatch.GetTimestamp());
						}
						if (OpenTrackPacket.TryParsePosition(array, out var position))
						{
							_positionX = position.X;
							_positionY = position.Y;
							_positionZ = position.Z;
						}
						_isRemoteConnection = !IPAddress.IsLoopback(remoteEP.Address);
						_isConnected = true;
						_consecutiveTimeouts = 0;
					}
				}
				catch (SocketException ex)
				{
					if (ex.SocketErrorCode == SocketError.TimedOut)
					{
						_consecutiveTimeouts++;
						if (_consecutiveTimeouts >= 50)
						{
							_isConnected = false;
						}
					}
					else if (ex.SocketErrorCode == SocketError.Interrupted)
					{
						break;
					}
				}
				catch (ObjectDisposedException)
				{
					break;
				}
			}
		}

		public void Dispose()
		{
			if (!_disposed)
			{
				_disposed = true;
				Stop();
			}
		}
	}
}
namespace CameraUnlock.Core.Processing
{
	public sealed class CenterOffsetManager
	{
		private TrackingPose _centerOffset;

		private Quat4 _centerQuaternionInverse = Quat4.Identity;

		private bool _hasValidCenter;

		public TrackingPose CenterOffset => _centerOffset;

		public bool HasValidCenter => _hasValidCenter;

		public void SetCenter(TrackingPose pose)
		{
			_centerOffset = new TrackingPose(pose.Yaw, pose.Pitch, pose.Roll, 0L);
			_centerQuaternionInverse = QuaternionUtils.FromYawPitchRoll(pose.Yaw, pose.Pitch, pose.Roll).Inverse;
			_hasValidCenter = true;
		}

		public void SetCenter(float yaw, float pitch, float roll)
		{
			_centerOffset = new TrackingPose(yaw, pitch, roll, 0L);
			_centerQuaternionInverse = QuaternionUtils.FromYawPitchRoll(yaw, pitch, roll).Inverse;
			_hasValidCenter = true;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public TrackingPose ApplyOffset(TrackingPose pose)
		{
			if (!_hasValidCenter)
			{
				return pose;
			}
			return pose.SubtractOffset(_centerOffset);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public void ApplyOffset(float yaw, float pitch, float roll, out float outYaw, out float outPitch, out float outRoll)
		{
			if (!_hasValidCenter)
			{
				outYaw = yaw;
				outPitch = pitch;
				outRoll = roll;
			}
			else
			{
				outYaw = yaw - _centerOffset.Yaw;
				outPitch = pitch - _centerOffset.Pitch;
				outRoll = roll - _centerOffset.Roll;
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public Quat4 ApplyOffsetQuat(Quat4 inputQ)
		{
			if (!_hasValidCenter)
			{
				return inputQ;
			}
			return _centerQuaternionInverse * inputQ;
		}

		public void ComposeAdditionalOffset(Quat4 relativeQ)
		{
			_centerQuaternionInverse = relativeQ.Inverse * _centerQuaternionInverse;
			QuaternionUtils.ToEulerYXZ(_centerQuaternionInverse.Inverse, out var yaw, out var pitch, out var roll);
			_centerOffset = new TrackingPose(yaw, pitch, roll, 0L);
			_hasValidCenter = true;
		}

		public void Reset()
		{
			_centerOffset = default(TrackingPose);
			_centerQuaternionInverse = Quat4.Identity;
			_hasValidCenter = false;
		}
	}
	public interface IInfluenceModifier
	{
		float GetInfluence();

		void Reset();
	}
	public class CompositeInfluenceModifier : IInfluenceModifier
	{
		private readonly IInfluenceModifier[] _modifiers;

		public CompositeInfluenceModifier(params IInfluenceModifier[] modifiers)
		{
			_modifiers = modifiers ?? new IInfluenceModifier[0];
		}

		public float GetInfluence()
		{
			float num = 1f;
			for (int i = 0; i < _modifiers.Length; i++)
			{
				num *= _modifiers[i].GetInfluence();
				if (num <= 0f)
				{
					return 0f;
				}
			}
			return num;
		}

		public void Reset()
		{
			for (int i = 0; i < _modifiers.Length; i++)
			{
				_modifiers[i].Reset();
			}
		}
	}
	public class ToggleInfluenceModifier : IInfluenceModifier
	{
		private bool _enabled = true;

		public bool Enabled
		{
			get
			{
				return _enabled;
			}
			set
			{
				_enabled = value;
			}
		}

		public float GetInfluence()
		{
			if (!_enabled)
			{
				return 0f;
			}
			return 1f;
		}

		public void Reset()
		{
			_enabled = true;
		}
	}
	public interface ITrackingProcessor
	{
		TrackingPose Process(TrackingPose rawPose, float deltaTime);

		void Reset();
	}
	public sealed class PoseInterpolator
	{
		private const float IntervalBlend = 0.3f;

		private const float DefaultSampleInterval = 1f / 30f;

		private const float MinSampleInterval = 0.001f;

		private const float MaxSampleInterval = 0.2f;

		private float _fromYaw;

		private float _fromPitch;

		private float _fromRoll;

		private float _toYaw;

		private float _toPitch;

		private float _toRoll;

		private long _lastTimestampTicks;

		private float _progress;

		private float _sampleInterval = 1f / 30f;

		private float _timeSinceLastNewSample;

		private bool _hasFirstSample;

		private bool _hasSecondSample;

		public float MaxExtrapolationTime { get; set; } = 0.1f;


		public TrackingPose Update(TrackingPose rawPose, float deltaTime)
		{
			if (!rawPose.IsValid)
			{
				return rawPose;
			}
			_timeSinceLastNewSample += deltaTime;
			if (rawPose.TimestampTicks != _lastTimestampTicks)
			{
				if (!_hasFirstSample)
				{
					_fromYaw = rawPose.Yaw;
					_fromPitch = rawPose.Pitch;
					_fromRoll = rawPose.Roll;
					_toYaw = rawPose.Yaw;
					_toPitch = rawPose.Pitch;
					_toRoll = rawPose.Roll;
					_lastTimestampTicks = rawPose.TimestampTicks;
					_progress = 1f;
					_timeSinceLastNewSample = 0f;
					_hasFirstSample = true;
					return rawPose;
				}
				if (_timeSinceLastNewSample > 0.001f)
				{
					if (!_hasSecondSample)
					{
						_sampleInterval = _timeSinceLastNewSample;
						_hasSecondSample = true;
					}
					else
					{
						_sampleInterval += (_timeSinceLastNewSample - _sampleInterval) * 0.3f;
					}
					if (_sampleInterval < 0.001f)
					{
						_sampleInterval = 0.001f;
					}
					if (_sampleInterval > 0.2f)
					{
						_sampleInterval = 0.2f;
					}
				}
				float num = ((_progress > 1f) ? 1f : _progress);
				_fromYaw += (_toYaw - _fromYaw) * num;
				_fromPitch += (_toPitch - _fromPitch) * num;
				_fromRoll += (_toRoll - _fromRoll) * num;
				_toYaw = rawPose.Yaw;
				_toPitch = rawPose.Pitch;
				_toRoll = rawPose.Roll;
				_lastTimestampTicks = rawPose.TimestampTicks;
				_progress = 0f;
				_timeSinceLastNewSample = 0f;
			}
			_progress += deltaTime / _sampleInterval;
			float num2 = ((_progress > 1f) ? 1f : ((_progress < 0f) ? 0f : _progress));
			float yaw = _fromYaw + (_toYaw - _fromYaw) * num2;
			float pitch = _fromPitch + (_toPitch - _fromPitch) * num2;
			float roll = _fromRoll + (_toRoll - _fromRoll) * num2;
			return new TrackingPose(yaw, pitch, roll, rawPose.TimestampTicks);
		}

		public void Reset()
		{
			_fromYaw = 0f;
			_fromPitch = 0f;
			_fromRoll = 0f;
			_toYaw = 0f;
			_toPitch = 0f;
			_toRoll = 0f;
			_lastTimestampTicks = 0L;
			_progress = 0f;
			_sampleInterval = 1f / 30f;
			_timeSinceLastNewSample = 0f;
			_hasFirstSample = false;
			_hasSecondSample = false;
		}
	}
	public sealed class PositionInterpolator
	{
		private const float IntervalBlend = 0.3f;

		private const float DefaultSampleInterval = 1f / 30f;

		private const float MinSampleInterval = 0.001f;

		private const float MaxSampleInterval = 0.2f;

		private float _fromX;

		private float _fromY;

		private float _fromZ;

		private float _toX;

		private float _toY;

		private float _toZ;

		private long _lastTimestampTicks;

		private float _progress;

		private float _sampleInterval = 1f / 30f;

		private float _timeSinceLastNewSample;

		private bool _hasFirstSample;

		private bool _hasSecondSample;

		public float MaxExtrapolationTime { get; set; } = 0.1f;


		public PositionData Update(PositionData rawPosition, float deltaTime)
		{
			if (!rawPosition.IsValid)
			{
				return rawPosition;
			}
			_timeSinceLastNewSample += deltaTime;
			if (rawPosition.TimestampTicks != _lastTimestampTicks)
			{
				if (!_hasFirstSample)
				{
					_fromX = rawPosition.X;
					_fromY = rawPosition.Y;
					_fromZ = rawPosition.Z;
					_toX = rawPosition.X;
					_toY = rawPosition.Y;
					_toZ = rawPosition.Z;
					_lastTimestampTicks = rawPosition.TimestampTicks;
					_progress = 1f;
					_timeSinceLastNewSample = 0f;
					_hasFirstSample = true;
					return rawPosition;
				}
				if (_timeSinceLastNewSample > 0.001f)
				{
					if (!_hasSecondSample)
					{
						_sampleInterval = _timeSinceLastNewSample;
						_hasSecondSample = true;
					}
					else
					{
						_sampleInterval += (_timeSinceLastNewSample - _sampleInterval) * 0.3f;
					}
					if (_sampleInterval < 0.001f)
					{
						_sampleInterval = 0.001f;
					}
					if (_sampleInterval > 0.2f)
					{
						_sampleInterval = 0.2f;
					}
				}
				float num = ((_progress > 1f) ? 1f : _progress);
				_fromX += (_toX - _fromX) * num;
				_fromY += (_toY - _fromY) * num;
				_fromZ += (_toZ - _fromZ) * num;
				_toX = rawPosition.X;
				_toY = rawPosition.Y;
				_toZ = rawPosition.Z;
				_lastTimestampTicks = rawPosition.TimestampTicks;
				_progress = 0f;
				_timeSinceLastNewSample = 0f;
			}
			_progress += deltaTime / _sampleInterval;
			float num2 = ((_progress > 1f) ? 1f : ((_progress < 0f) ? 0f : _progress));
			float x = _fromX + (_toX - _fromX) * num2;
			float y = _fromY + (_toY - _fromY) * num2;
			float z = _fromZ + (_toZ - _fromZ) * num2;
			return new PositionData(x, y, z, rawPosition.TimestampTicks);
		}

		public void Reset()
		{
			_fromX = 0f;
			_fromY = 0f;
			_fromZ = 0f;
			_toX = 0f;
			_toY = 0f;
			_toZ = 0f;
			_lastTimestampTicks = 0L;
			_progress = 0f;
			_sampleInterval = 1f / 30f;
			_timeSinceLastNewSample = 0f;
			_hasFirstSample = false;
			_hasSecondSample = false;
		}
	}
	public sealed class PositionProcessor
	{
		private Vec3 _center;

		private Vec3 _smoothedPosition;

		private bool _hasSmoothedValue;

		public PositionSettings Settings { get; set; } = PositionSettings.Default;


		public float TrackerPivotForward { get; set; } = 0.01f;


		public Vec3 Process(PositionData raw, Quat4 processedRotationQ, float deltaTime)
		{
			if (!raw.IsValid)
			{
				return Vec3.Zero;
			}
			Vec3 vec = raw.ToVec3() - _center;
			if (TrackerPivotForward > 0f)
			{
				Vec3 vec2 = new Vec3(0f, 0f, TrackerPivotForward);
				Vec3 vec3 = processedRotationQ.Rotate(vec2) - vec2;
				vec -= vec3;
			}
			float num = vec.X * Settings.SensitivityX;
			float num2 = vec.Y * Settings.SensitivityY;
			float num3 = vec.Z * Settings.SensitivityZ;
			if (Settings.InvertX)
			{
				num = 0f - num;
			}
			if (Settings.InvertY)
			{
				num2 = 0f - num2;
			}
			if (Settings.InvertZ)
			{
				num3 = 0f - num3;
			}
			Vec3 smoothedPosition = new Vec3(num, num2, num3);
			float effectiveSmoothing = SmoothingUtils.GetEffectiveSmoothing(Settings.Smoothing);
			if (!_hasSmoothedValue)
			{
				_smoothedPosition = smoothedPosition;
				_hasSmoothedValue = true;
			}
			else
			{
				float t = SmoothingUtils.CalculateSmoothingFactor(effectiveSmoothing, deltaTime);
				_smoothedPosition = new Vec3(MathUtils.Lerp(_smoothedPosition.X, smoothedPosition.X, t), MathUtils.Lerp(_smoothedPosition.Y, smoothedPosition.Y, t), MathUtils.Lerp(_smoothedPosition.Z, smoothedPosition.Z, t));
			}
			return new Vec3(MathUtils.Clamp(_smoothedPosition.X, 0f - Settings.LimitX, Settings.LimitX), MathUtils.Clamp(_smoothedPosition.Y, 0f - Settings.LimitY, Settings.LimitY), MathUtils.Clamp(_smoothedPosition.Z, 0f - Settings.LimitZBack, Settings.LimitZ));
		}

		public void SetCenter(PositionData centerPosition)
		{
			_center = centerPosition.ToVec3();
		}

		public void ResetSmoothing()
		{
			_smoothedPosition = Vec3.Zero;
			_hasSmoothedValue = false;
		}

		public void Reset()
		{
			_center = Vec3.Zero;
			_smoothedPosition = Vec3.Zero;
			_hasSmoothedValue = false;
		}
	}
	public sealed class SmoothedEulerState
	{
		private Quat4 _smoothed;

		private bool _initialized;

		public void Update(float yaw, float pitch, float roll, float smoothing, float deltaTime, out float smoothedYaw, out float smoothedPitch, out float smoothedRoll)
		{
			if (smoothing < 0.001f)
			{
				_initialized = false;
				smoothedYaw = yaw;
				smoothedPitch = pitch;
				smoothedRoll = roll;
				return;
			}
			Quat4 quat = QuaternionUtils.FromYawPitchRoll(yaw, pitch, roll);
			if (!_initialized)
			{
				_smoothed = quat;
				_initialized = true;
				smoothedYaw = yaw;
				smoothedPitch = pitch;
				smoothedRoll = roll;
			}
			else
			{
				float t = SmoothingUtils.CalculateSmoothingFactor(smoothing, deltaTime);
				_smoothed = QuaternionUtils.Slerp(_smoothed, quat, t);
				QuaternionUtils.ToEulerYXZ(_smoothed, out smoothedYaw, out smoothedPitch, out smoothedRoll);
			}
		}

		public void Reset()
		{
			_smoothed = Quat4.Identity;
			_initialized = false;
		}
	}
	public sealed class TrackingProcessor : ITrackingProcessor
	{
		private readonly CenterOffsetManager _centerManager = new CenterOffsetManager();

		private float _smoothedYaw;

		private float _smoothedPitch;

		private float _smoothedRoll;

		private bool _hasSmoothedValue;

		public SensitivitySettings Sensitivity { get; set; } = SensitivitySettings.Default;


		public DeadzoneSettings Deadzone { get; set; } = DeadzoneSettings.None;


		public float SmoothingFactor { get; set; }

		public CenterOffsetManager CenterManager => _centerManager;

		public void GetSmoothedRotation(out float yaw, out float pitch, out float roll)
		{
			yaw = _smoothedYaw;
			pitch = _smoothedPitch;
			roll = _smoothedRoll;
		}

		public TrackingPose Process(TrackingPose rawPose, float deltaTime)
		{
			if (!rawPose.IsValid)
			{
				return rawPose;
			}
			Quat4 inputQ = QuaternionUtils.FromYawPitchRoll(rawPose.Yaw, rawPose.Pitch, rawPose.Roll);
			QuaternionUtils.ToEulerYXZ(_centerManager.ApplyOffsetQuat(inputQ), out var yaw, out var pitch, out var roll);
			yaw = DeadzoneUtils.Apply(yaw, Deadzone.Yaw);
			pitch = DeadzoneUtils.Apply(pitch, Deadzone.Pitch);
			roll = DeadzoneUtils.Apply(roll, Deadzone.Roll);
			float effectiveSmoothing = SmoothingUtils.GetEffectiveSmoothing(SmoothingFactor);
			if (!_hasSmoothedValue)
			{
				_smoothedYaw = yaw;
				_smoothedPitch = pitch;
				_smoothedRoll = roll;
				_hasSmoothedValue = true;
			}
			else
			{
				_smoothedYaw = SmoothingUtils.Smooth(_smoothedYaw, yaw, effectiveSmoothing, deltaTime);
				_smoothedPitch = SmoothingUtils.Smooth(_smoothedPitch, pitch, effectiveSmoothing, deltaTime);
				_smoothedRoll = SmoothingUtils.Smooth(_smoothedRoll, roll, effectiveSmoothing, deltaTime);
			}
			return new TrackingPose(_smoothedYaw, _smoothedPitch, _smoothedRoll, rawPose.TimestampTicks).ApplySensitivity(Sensitivity);
		}

		public void Recenter()
		{
			Quat4 relativeQ = QuaternionUtils.FromYawPitchRoll(_smoothedYaw, _smoothedPitch, _smoothedRoll);
			_centerManager.ComposeAdditionalOffset(relativeQ);
			_smoothedYaw = 0f;
			_smoothedPitch = 0f;
			_smoothedRoll = 0f;
		}

		public void RecenterTo(TrackingPose pose)
		{
			_centerManager.SetCenter(pose);
			_smoothedYaw = 0f;
			_smoothedPitch = 0f;
			_smoothedRoll = 0f;
		}

		public void ResetSmoothing()
		{
			_smoothedYaw = 0f;
			_smoothedPitch = 0f;
			_smoothedRoll = 0f;
			_hasSmoothedValue = false;
		}

		public void Reset()
		{
			_centerManager.Reset();
			_smoothedYaw = 0f;
			_smoothedPitch = 0f;
			_smoothedRoll = 0f;
			_hasSmoothedValue = false;
		}
	}
}
namespace CameraUnlock.Core.Processing.AxisTransform
{
	public enum AxisSource
	{
		Yaw,
		Pitch,
		Roll,
		X,
		Y,
		Z,
		None
	}
	public enum TargetAxis
	{
		Yaw,
		Pitch,
		Roll
	}
	public class AxisConfig
	{
		public AxisSource Source { get; set; }

		public TargetAxis Target { get; set; }

		public float Sensitivity { get; set; } = 1f;


		public bool Inverted { get; set; }

		public float DeadzoneMin { get; set; }

		public float DeadzoneMax { get; set; }

		public float MinLimit { get; set; } = -180f;


		public float MaxLimit { get; set; } = 180f;


		public bool EnableLimits { get; set; }

		public SensitivityCurve SensitivityCurve { get; set; }

		public float CurveStrength { get; set; } = 1f;


		public Func<float, float> CustomCurveFunc { get; set; }

		public float MaxInputRange { get; set; } = 180f;


		public float TransformValue(float input)
		{
			if (Source == AxisSource.None)
			{
				return 0f;
			}
			input = ApplyDeadzone(input);
			float num = ApplySensitivityCurve(input);
			float num2 = input * Sensitivity * num;
			if (Inverted)
			{
				num2 = 0f - num2;
			}
			if (EnableLimits)
			{
				num2 = System.Math.Max(MinLimit, System.Math.Min(MaxLimit, num2));
			}
			return num2;
		}

		private float ApplyDeadzone(float input)
		{
			float num = System.Math.Abs(input);
			float num2 = ((input >= 0f) ? 1f : (-1f));
			if (num < DeadzoneMin)
			{
				return 0f;
			}
			if (DeadzoneMax > DeadzoneMin && num < DeadzoneMax)
			{
				float num3 = DeadzoneMax - DeadzoneMin;
				float num4 = (num - DeadzoneMin) / num3;
				return num2 * num4 * DeadzoneMax;
			}
			return input;
		}

		private float ApplySensitivityCurve(float input)
		{
			float val = System.Math.Abs(input) / MaxInputRange;
			val = System.Math.Max(0f, System.Math.Min(1f, val));
			return SensitivityCurveUtils.ApplyCurve(SensitivityCurve, val, CurveStrength, CustomCurveFunc);
		}

		public AxisConfig Clone()
		{
			return new AxisConfig
			{
				Source = Source,
				Target = Target,
				Sensitivity = Sensitivity,
				Inverted = Inverted,
				DeadzoneMin = DeadzoneMin,
				DeadzoneMax = DeadzoneMax,
				MinLimit = MinLimit,
				MaxLimit = MaxLimit,
				EnableLimits = EnableLimits,
				SensitivityCurve = SensitivityCurve,
				CurveStrength = CurveStrength,
				CustomCurveFunc = CustomCurveFunc,
				MaxInputRange = MaxInputRange
			};
		}
	}
	public class MappingConfig
	{
		public AxisConfig YawConfig { get; set; }

		public AxisConfig PitchConfig { get; set; }

		public AxisConfig RollConfig { get; set; }

		public MappingConfig()
		{
			YawConfig = new AxisConfig
			{
				Source = AxisSource.Yaw,
				Target = TargetAxis.Yaw
			};
			PitchConfig = new AxisConfig
			{
				Source = AxisSource.Pitch,
				Target = TargetAxis.Pitch
			};
			RollConfig = new AxisConfig
			{
				Source = AxisSource.Roll,
				Target = TargetAxis.Roll
			};
		}

		public void ApplyMapping(float[] rawData, out float yaw, out float pitch, out float roll)
		{
			if (rawData == null || rawData.Length < 6)
			{
				throw new ArgumentException("rawData must contain at least 6 elements [yaw, pitch, roll, x, y, z]", "rawData");
			}
			yaw = ApplyAxisMapping(YawConfig, rawData);
			pitch = ApplyAxisMapping(PitchConfig, rawData);
			roll = ApplyAxisMapping(RollConfig, rawData);
		}

		public void ApplyMapping(float rawYaw, float rawPitch, float rawRoll, out float yaw, out float pitch, out float roll)
		{
			yaw = ApplyAxisMappingDirect(YawConfig, rawYaw, rawPitch, rawRoll);
			pitch = ApplyAxisMappingDirect(PitchConfig, rawYaw, rawPitch, rawRoll);
			roll = ApplyAxisMappingDirect(RollConfig, rawYaw, rawPitch, rawRoll);
		}

		private float ApplyAxisMappingDirect(AxisConfig config, float rawYaw, float rawPitch, float rawRoll)
		{
			float input;
			switch (config.Source)
			{
			case AxisSource.None:
				return 0f;
			case AxisSource.Yaw:
				input = rawYaw;
				break;
			case AxisSource.Pitch:
				input = rawPitch;
				break;
			case AxisSource.Roll:
				input = rawRoll;
				break;
			default:
				input = 0f;
				break;
			}
			return config.TransformValue(input);
		}

		private float ApplyAxisMapping(AxisConfig config, float[] rawData)
		{
			if (config.Source == AxisSource.None)
			{
				return 0f;
			}
			return config.TransformValue(config.Source switch
			{
				AxisSource.Yaw => rawData[0], 
				AxisSource.Pitch => rawData[1], 
				AxisSource.Roll => rawData[2], 
				AxisSource.X => rawData[3], 
				AxisSource.Y => rawData[4], 
				AxisSource.Z => rawData[5], 
				_ => 0f, 
			});
		}

		public void ResetToDefault()
		{
			YawConfig = new AxisConfig
			{
				Source = AxisSource.Yaw,
				Target = TargetAxis.Yaw,
				Sensitivity = 1f
			};
			PitchConfig = new AxisConfig
			{
				Source = AxisSource.Pitch,
				Target = TargetAxis.Pitch,
				Sensitivity = 1f
			};
			RollConfig = new AxisConfig
			{
				Source = AxisSource.Roll,
				Target = TargetAxis.Roll,
				Sensitivity = 1f
			};
		}

		public void LoadPreset(MappingPreset preset)
		{
			MappingPresets.ApplyPreset(this, preset);
		}

		public MappingConfig Clone()
		{
			return new MappingConfig
			{
				YawConfig = (YawConfig?.Clone() ?? new AxisConfig
				{
					Source = AxisSource.Yaw,
					Target = TargetAxis.Yaw
				}),
				PitchConfig = (PitchConfig?.Clone() ?? new AxisConfig
				{
					Source = AxisSource.Pitch,
					Target = TargetAxis.Pitch
				}),
				RollConfig = (RollConfig?.Clone() ?? new AxisConfig
				{
					Source = AxisSource.Roll,
					Target = TargetAxis.Roll
				})
			};
		}
	}
	public enum MappingPreset
	{
		Default,
		InvertedPitch,
		NoRoll,
		HighSensitivity,
		LowSensitivity,
		Competitive,
		Simulation
	}
	public static class MappingPresets
	{
		public static void ApplyPreset(MappingConfig config, MappingPreset preset)
		{
			if (config == null)
			{
				throw new ArgumentNullException("config");
			}
			config.ResetToDefault();
			switch (preset)
			{
			case MappingPreset.InvertedPitch:
				config.PitchConfig.Inverted = true;
				break;
			case MappingPreset.NoRoll:
				config.RollConfig.Source = AxisSource.None;
				break;
			case MappingPreset.HighSensitivity:
				config.YawConfig.Sensitivity = 1.5f;
				config.PitchConfig.Sensitivity = 1.5f;
				config.RollConfig.Sensitivity = 1.2f;
				break;
			case MappingPreset.LowSensitivity:
				config.YawConfig.Sensitivity = 0.7f;
				config.PitchConfig.Sensitivity = 0.7f;
				config.RollConfig.Sensitivity = 0.5f;
				break;
			case MappingPreset.Competitive:
				config.YawConfig.Sensitivity = 1.2f;
				config.YawConfig.SensitivityCurve = SensitivityCurve.Quadratic;
				config.YawConfig.CurveStrength = 0.5f;
				config.YawConfig.DeadzoneMin = 0.5f;
				config.PitchConfig.Sensitivity = 0.9f;
				config.PitchConfig.DeadzoneMin = 0.5f;
				config.RollConfig.Source = AxisSource.None;
				break;
			case MappingPreset.Simulation:
				config.YawConfig.SensitivityCurve = SensitivityCurve.SCurve;
				config.YawConfig.CurveStrength = 0.7f;
				config.PitchConfig.SensitivityCurve = SensitivityCurve.SCurve;
				config.PitchConfig.CurveStrength = 0.7f;
				config.RollConfig.SensitivityCurve = SensitivityCurve.SCurve;
				config.RollConfig.CurveStrength = 0.7f;
				break;
			case MappingPreset.Default:
				break;
			}
		}

		public static MappingConfig CreateFromPreset(MappingPreset preset)
		{
			MappingConfig mappingConfig = new MappingConfig();
			ApplyPreset(mappingConfig, preset);
			return mappingConfig;
		}
	}
	public enum SensitivityCurve
	{
		Linear,
		Quadratic,
		Cubic,
		Exponential,
		Logarithmic,
		SCurve,
		Custom
	}
	public static class SensitivityCurveUtils
	{
		private const double Exp2Minus1 = 6.38905609893065;

		public static float ApplyCurve(SensitivityCurve curve, float normalizedInput, float strength, Func<float, float> customCurveFunc = null)
		{
			normalizedInput = System.Math.Max(0f, System.Math.Min(1f, normalizedInput));
			float b;
			switch (curve)
			{
			case SensitivityCurve.Linear:
				b = 1f;
				break;
			case SensitivityCurve.Quadratic:
				b = normalizedInput * normalizedInput;
				break;
			case SensitivityCurve.Cubic:
				b = normalizedInput * normalizedInput * normalizedInput;
				break;
			case SensitivityCurve.Exponential:
				b = (float)((System.Math.Exp((double)normalizedInput * 2.0) - 1.0) / 6.38905609893065);
				break;
			case SensitivityCurve.Logarithmic:
				b = (float)System.Math.Log10((double)normalizedInput * 9.0 + 1.0);
				break;
			case SensitivityCurve.SCurve:
				b = normalizedInput * normalizedInput * (3f - 2f * normalizedInput);
				break;
			case SensitivityCurve.Custom:
				if (customCurveFunc == null)
				{
					throw new ArgumentException("Custom curve function must be provided when using SensitivityCurve.Custom", "customCurveFunc");
				}
				b = customCurveFunc(normalizedInput);
				break;
			default:
				b = 1f;
				break;
			}
			return MathUtils.Lerp(1f, b, strength);
		}
	}
}
namespace CameraUnlock.Core.Math
{
	public static class AngleUtils
	{
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static float NormalizeAngle(float angle)
		{
			if (angle >= -180f && angle <= 180f)
			{
				return angle;
			}
			angle %= 360f;
			if (angle > 180f)
			{
				angle -= 360f;
			}
			else if (angle < -180f)
			{
				angle += 360f;
			}
			return angle;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static double NormalizeAngle(double angle)
		{
			if (angle >= -180.0 && angle <= 180.0)
			{
				return angle;
			}
			angle %= 360.0;
			if (angle > 180.0)
			{
				angle -= 360.0;
			}
			else if (angle < -180.0)
			{
				angle += 360.0;
			}
			return angle;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static float ShortestAngleDelta(float from, float to)
		{
			return NormalizeAngle(to - from);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static float ToRadians(float degrees)
		{
			return degrees * ((float)System.Math.PI / 180f);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static float ToDegrees(float radians)
		{
			return radians * (180f / (float)System.Math.PI);
		}
	}
	public static class DeadzoneUtils
	{
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static float Apply(float value, float deadzone)
		{
			if (deadzone <= 0f)
			{
				return value;
			}
			float num = ((value >= 0f) ? value : (0f - value));
			if (num <= deadzone)
			{
				return 0f;
			}
			return ((value >= 0f) ? 1f : (-1f)) * (num - deadzone);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static double Apply(double value, double deadzone)
		{
			if (deadzone <= 0.0)
			{
				return value;
			}
			double num = ((value >= 0.0) ? value : (0.0 - value));
			if (num <= deadzone)
			{
				return 0.0;
			}
			return ((value >= 0.0) ? 1.0 : (-1.0)) * (num - deadzone);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static TrackingPose Apply(TrackingPose pose, DeadzoneSettings deadzone)
		{
			return new TrackingPose(Apply(pose.Yaw, deadzone.Yaw), Apply(pose.Pitch, deadzone.Pitch), Apply(pose.Roll, deadzone.Roll), pose.TimestampTicks);
		}
	}
	public static class MathConstants
	{
		public const float Pi = (float)System.Math.PI;

		public const float TwoPi = (float)System.Math.PI * 2f;

		public const float DegToRad = (float)System.Math.PI / 180f;

		public const float RadToDeg = 180f / (float)System.Math.PI;
	}
	public static class MathUtils
	{
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static float Clamp(float value, float min, float max)
		{
			if (value < min)
			{
				return min;
			}
			if (value > max)
			{
				return max;
			}
			return value;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static float Clamp01(float value)
		{
			if (value < 0f)
			{
				return 0f;
			}
			if (value > 1f)
			{
				return 1f;
			}
			return value;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static float Lerp(float a, float b, float t)
		{
			return a + (b - a) * t;
		}
	}
	public static class QuaternionUtils
	{
		private const float DegToHalfRad = (float)System.Math.PI / 360f;

		private const float SlerpLinearThreshold = 0.9995f;

		private const float NormalizationEpsilon = 0.0001f;

		public static readonly Quat4 Identity = Quat4.Identity;

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Quat4 FromYawPitchRoll(float yaw, float pitch, float roll)
		{
			float num = yaw * ((float)System.Math.PI / 360f);
			float num2 = pitch * ((float)System.Math.PI / 360f);
			float num3 = roll * ((float)System.Math.PI / 360f);
			float num4 = (float)System.Math.Cos(num);
			float num5 = (float)System.Math.Sin(num);
			float num6 = (float)System.Math.Cos(num2);
			float num7 = (float)System.Math.Sin(num2);
			float num8 = (float)System.Math.Cos(num3);
			float num9 = (float)System.Math.Sin(num3);
			float w = num4 * num6 * num8 + num5 * num7 * num9;
			float x = num4 * num7 * num8 + num5 * num6 * num9;
			float y = num5 * num6 * num8 - num4 * num7 * num9;
			float z = num4 * num6 * num9 - num5 * num7 * num8;
			return new Quat4(x, y, z, w);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Quat4 Multiply(Quat4 a, Quat4 b)
		{
			return new Quat4(a.W * b.X + a.X * b.W + a.Y * b.Z - a.Z * b.Y, a.W * b.Y - a.X * b.Z + a.Y * b.W + a.Z * b.X, a.W * b.Z + a.X * b.Y - a.Y * b.X + a.Z * b.W, a.W * b.W - a.X * b.X - a.Y * b.Y - a.Z * b.Z);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Quat4 Inverse(Quat4 q)
		{
			return q.Inverse;
		}

		public static Quat4 Slerp(Quat4 a, Quat4 b, float t)
		{
			float num = a.Dot(b);
			float num2 = 1f;
			if (num < 0f)
			{
				num2 = -1f;
				num = 0f - num;
			}
			if (num > 0.9995f)
			{
				return Normalize(new Quat4(a.X + t * (num2 * b.X - a.X), a.Y + t * (num2 * b.Y - a.Y), a.Z + t * (num2 * b.Z - a.Z), a.W + t * (num2 * b.W - a.W)));
			}
			float num3 = (float)System.Math.Acos(num);
			float num4 = (float)System.Math.Sin(num3);
			float num5 = 1f / num4;
			float num6 = (float)System.Math.Sin((1f - t) * num3) * num5;
			float num7 = num2 * (float)System.Math.Sin(t * num3) * num5;
			return new Quat4(num6 * a.X + num7 * b.X, num6 * a.Y + num7 * b.Y, num6 * a.Z + num7 * b.Z, num6 * a.W + num7 * b.W);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Quat4 Normalize(Quat4 q)
		{
			float num = q.X * q.X + q.Y * q.Y + q.Z * q.Z + q.W * q.W;
			if (num < 9.999999E-09f)
			{
				return Quat4.Identity;
			}
			float num2 = 1f / (float)System.Math.Sqrt(num);
			return new Quat4(q.X * num2, q.Y * num2, q.Z * num2, q.W * num2);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void ToEulerYXZ(Quat4 q, out float yaw, out float pitch, out float roll)
		{
			float num = 2f * (q.W * q.X - q.Y * q.Z);
			if (num >= 1f)
			{
				pitch = 90f;
				yaw = (float)(System.Math.Atan2(2f * (q.X * q.Z + q.W * q.Y), 1f - 2f * (q.X * q.X + q.Y * q.Y)) * 57.2957763671875);
				roll = 0f;
			}
			else if (num <= -1f)
			{
				pitch = -90f;
				yaw = (float)(System.Math.Atan2(2f * (q.X * q.Z + q.W * q.Y), 1f - 2f * (q.X * q.X + q.Y * q.Y)) * 57.2957763671875);
				roll = 0f;
			}
			else
			{
				pitch = (float)(System.Math.Asin(num) * 57.2957763671875);
				yaw = (float)(System.Math.Atan2(2f * (q.X * q.Z + q.W * q.Y), 1f - 2f * (q.X * q.X + q.Y * q.Y)) * 57.2957763671875);
				roll = (float)(System.Math.Atan2(2f * (q.X * q.Y + q.W * q.Z), 1f - 2f * (q.X * q.X + q.Z * q.Z)) * 57.2957763671875);
			}
		}
	}
	public static class SmoothingUtils
	{
		public const float BaselineSmoothing = 0.15f;

		public const float FrameInterpolationSpeed = 50f;

		private const float MaxSmoothing = 0.1f;

		private const float SpeedRange = 49.9f;

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static float CalculateSmoothingFactor(float smoothing, float deltaTime)
		{
			float num = 50f - 49.9f * smoothing;
			if (num > 50f)
			{
				num = 50f;
			}
			if (num < 0.1f)
			{
				num = 0.1f;
			}
			return 1f - (float)System.Math.Exp((0f - num) * deltaTime);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static float Smooth(float current, float target, float smoothing, float deltaTime)
		{
			float num = CalculateSmoothingFactor(smoothing, deltaTime);
			return current + (target - current) * num;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static double Smooth(double current, double target, float smoothing, float deltaTime)
		{
			float num = CalculateSmoothingFactor(smoothing, deltaTime);
			return current + (target - current) * (double)num;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static float GetEffectiveSmoothing(float baseSmoothing)
		{
			if (baseSmoothing < 0.15f)
			{
				return 0.15f;
			}
			return baseSmoothing;
		}
	}
}
namespace CameraUnlock.Core.Input
{
	public interface IHotkeyListener
	{
		void OnHotkeyToggle(bool enabled);

		void OnHotkeyRecenter();
	}
	public delegate bool KeyDownCheck(int keyCode);
	public delegate bool TextInputActiveCheck();
	public delegate void ToggleEventHandler(bool enabled);
	public delegate void RecenterEventHandler();
	public sealed class HotkeyHandler
	{
		private readonly KeyDownCheck _keyDownCheck;

		private readonly TextInputActiveCheck _textInputCheck;

		private readonly IHotkeyListener _listener;

		private readonly float _cooldownSeconds;

		private int _toggleKeyCode;

		private int _recenterKeyCode;

		private float _lastToggleTime;

		private float _lastRecenterTime;

		private bool _isEnabled = true;

		private int _toggleCount;

		private int _recenterCount;

		public bool IsEnabled
		{
			get
			{
				return _isEnabled;
			}
			set
			{
				_isEnabled = value;
			}
		}

		public int ToggleCount => _toggleCount;

		public int RecenterCount => _recenterCount;

		public event ToggleEventHandler OnToggled;

		[Obsolete("Use OnToggled or IHotkeyListener instead")]
		public event RecenterEventHandler OnToggle;

		public event RecenterEventHandler OnRecenter;

		public HotkeyHandler(KeyDownCheck keyDownCheck, TextInputActiveCheck textInputCheck = null, float cooldownSeconds = 0.3f)
			: this(keyDownCheck, textInputCheck, null, cooldownSeconds)
		{
		}

		public HotkeyHandler(KeyDownCheck keyDownCheck, TextInputActiveCheck textInputCheck, IHotkeyListener listener, float cooldownSeconds = 0.3f)
		{
			_keyDownCheck = keyDownCheck;
			_textInputCheck = textInputCheck;
			_listener = listener;
			_cooldownSeconds = cooldownSeconds;
		}

		public void SetToggleKey(int keyCode)
		{
			_toggleKeyCode = keyCode;
		}

		public void SetRecenterKey(int keyCode)
		{
			_recenterKeyCode = keyCode;
		}

		public void Update(float currentTime)
		{
			if (_textInputCheck != null && _textInputCheck())
			{
				return;
			}
			if (_toggleKeyCode != 0 && _keyDownCheck(_toggleKeyCode) && currentTime - _lastToggleTime >= _cooldownSeconds)
			{
				_lastToggleTime = currentTime;
				_toggleCount++;
				_isEnabled = !_isEnabled;
				if (_listener != null)
				{
					_listener.OnHotkeyToggle(_isEnabled);
				}
				if (this.OnToggled != null)
				{
					this.OnToggled(_isEnabled);
				}
				if (this.OnToggle != null)
				{
					this.OnToggle();
				}
			}
			if (_recenterKeyCode != 0 && _keyDownCheck(_recenterKeyCode) && currentTime - _lastRecenterTime >= _cooldownSeconds)
			{
				_lastRecenterTime = currentTime;
				_recenterCount++;
				if (_listener != null)
				{
					_listener.OnHotkeyRecenter();
				}
				if (this.OnRecenter != null)
				{
					this.OnRecenter();
				}
			}
		}

		public bool Toggle()
		{
			_toggleCount++;
			_isEnabled = !_isEnabled;
			if (_listener != null)
			{
				_listener.OnHotkeyToggle(_isEnabled);
			}
			if (this.OnToggled != null)
			{
				this.OnToggled(_isEnabled);
			}
			if (this.OnToggle != null)
			{
				this.OnToggle();
			}
			return _isEnabled;
		}

		public void ResetCounts()
		{
			_toggleCount = 0;
			_recenterCount = 0;
		}
	}
	public static class CommonKeyCodes
	{
		public const int None = 0;

		public const int Home = 278;

		public const int End = 279;

		public const int F1 = 282;

		public const int F2 = 283;

		public const int F3 = 284;

		public const int F4 = 285;

		public const int F5 = 286;

		public const int F6 = 287;

		public const int F7 = 288;

		public const int F8 = 289;

		public const int F9 = 290;

		public const int F10 = 291;

		public const int F11 = 292;

		public const int F12 = 293;
	}
}
namespace CameraUnlock.Core.Diagnostics
{
	public sealed class PerformanceMonitor
	{
		private static readonly double TicksToMicroseconds = 1000000.0 / (double)Stopwatch.Frequency;

		private readonly long[] _samples;

		private readonly int _sampleCount;

		private int _sampleIndex;

		private int _validSampleCount;

		private long _runningSum;

		private readonly Stopwatch _stopwatch;

		private long _currentStart;

		public double AverageMicroseconds
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				if (_validSampleCount == 0)
				{
					return 0.0;
				}
				return (double)_runningSum / (double)_validSampleCount * TicksToMicroseconds;
			}
		}

		public PerformanceMonitor(int sampleCount = 60)
		{
			_sampleCount = ((sampleCount > 0) ? sampleCount : 60);
			_samples = new long[_sampleCount];
			_stopwatch = new Stopwatch();
			_stopwatch.Start();
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public void BeginTiming()
		{
			_currentStart = _stopwatch.ElapsedTicks;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public void EndTiming()
		{
			long ticks = _stopwatch.ElapsedTicks - _currentStart;
			RecordTicksInternal(ticks);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public void RecordTicks(long ticks)
		{
			RecordTicksInternal(ticks);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private void RecordTicksInternal(long ticks)
		{
			long num = _samples[_sampleIndex];
			_runningSum -= num;
			_runningSum += ticks;
			if (num == 0L && ticks > 0)
			{
				_validSampleCount++;
			}
			else if (num > 0 && ticks == 0L)
			{
				_validSampleCount--;
			}
			_samples[_sampleIndex] = ticks;
			_sampleIndex = (_sampleIndex + 1) % _sampleCount;
		}

		public void Reset()
		{
			for (int i = 0; i < _samples.Length; i++)
			{
				_samples[i] = 0L;
			}
			_sampleIndex = 0;
			_validSampleCount = 0;
			_runningSum = 0L;
		}

		public string GetReport(string label)
		{
			return $"{label}: {AverageMicroseconds:F1}µs";
		}
	}
	public static class PerformanceStats
	{
		private static readonly double TicksPerMicrosecond = (double)Stopwatch.Frequency / 1000000.0;

		private static long _totalFrames;

		private static long _trackedFrames;

		private static long _skippedFrames;

		private static long _totalTrackingTicks;

		private static long _maxTrackingTicks;

		private static long _packetsReceived;

		private static long _packetsDropped;

		public static long TotalFrames => Interlocked.Read(ref _totalFrames);

		public static long TrackedFrames => Interlocked.Read(ref _trackedFrames);

		public static long SkippedFrames => Interlocked.Read(ref _skippedFrames);

		public static double AverageTrackingMicroseconds
		{
			get
			{
				long num = Interlocked.Read(ref _trackedFrames);
				if (num == 0L)
				{
					return 0.0;
				}
				return (double)Interlocked.Read(ref _totalTrackingTicks) / TicksPerMicrosecond / (double)num;
			}
		}

		public static double MaxTrackingMicroseconds => (double)Interlocked.Read(ref _maxTrackingTicks) / TicksPerMicrosecond;

		public static long PacketsReceived => Interlocked.Read(ref _packetsReceived);

		public static long PacketsDropped => Interlocked.Read(ref _packetsDropped);

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void RecordTrackedFrame(long elapsedTicks)
		{
			Interlocked.Increment(ref _totalFrames);
			Interlocked.Increment(ref _trackedFrames);
			Interlocked.Add(ref _totalTrackingTicks, elapsedTicks);
			long num;
			do
			{
				num = Interlocked.Read(ref _maxTrackingTicks);
			}
			while (elapsedTicks > num && Interlocked.CompareExchange(ref _maxTrackingTicks, elapsedTicks, num) != num);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void RecordSkippedFrame()
		{
			Interlocked.Increment(ref _totalFrames);
			Interlocked.Increment(ref _skippedFrames);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void RecordPacketReceived()
		{
			Interlocked.Increment(ref _packetsReceived);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static void RecordPacketDropped()
		{
			Interlocked.Increment(ref _packetsDropped);
		}

		public static void Reset()
		{
			Interlocked.Exchange(ref _totalFrames, 0L);
			Interlocked.Exchange(ref _trackedFrames, 0L);
			Interlocked.Exchange(ref _skippedFrames, 0L);
			Interlocked.Exchange(ref _totalTrackingTicks, 0L);
			Interlocked.Exchange(ref _maxTrackingTicks, 0L);
			Interlocked.Exchange(ref _packetsReceived, 0L);
			Interlocked.Exchange(ref _packetsDropped, 0L);
		}

		public static string GetSummary()
		{
			return $"Frames: {TotalFrames} total, {TrackedFrames} tracked, {SkippedFrames} skipped | Tracking: {AverageTrackingMicroseconds:F1}us avg, {MaxTrackingMicroseconds:F1}us max | UDP: {PacketsReceived} received, {PacketsDropped} dropped";
		}
	}
}
namespace CameraUnlock.Core.Data
{
	public sealed class CoordinateTransformer
	{
		public AxisMapping YawMapping { get; set; }

		public AxisMapping PitchMapping { get; set; }

		public AxisMapping RollMapping { get; set; }

		public CoordinateTransformer()
		{
			YawMapping = new AxisMapping(SourceAxis.Yaw, invert: false);
			PitchMapping = new AxisMapping(SourceAxis.Pitch, invert: false);
			RollMapping = new AxisMapping(SourceAxis.Roll, invert: false);
		}

		public CoordinateTransformer(AxisMapping yaw, AxisMapping pitch, AxisMapping roll)
		{
			YawMapping = yaw;
			PitchMapping = pitch;
			RollMapping = roll;
		}

		public TrackingPose Transform(TrackingPose pose)
		{
			return new TrackingPose(ApplyMapping(pose, YawMapping), ApplyMapping(pose, PitchMapping), ApplyMapping(pose, RollMapping), pose.TimestampTicks);
		}

		public void Transform(float yaw, float pitch, float roll, out float outYaw, out float outPitch, out float outRoll)
		{
			outYaw = ApplyMapping(yaw, pitch, roll, YawMapping);
			outPitch = ApplyMapping(yaw, pitch, roll, PitchMapping);
			outRoll = ApplyMapping(yaw, pitch, roll, RollMapping);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private static float ApplyMapping(TrackingPose pose, AxisMapping mapping)
		{
			return ApplyMapping(pose.Yaw, pose.Pitch, pose.Roll, mapping);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private static float ApplyMapping(float yaw, float pitch, float roll, AxisMapping mapping)
		{
			float num = mapping.Source switch
			{
				SourceAxis.Yaw => yaw, 
				SourceAxis.Pitch => pitch, 
				SourceAxis.Roll => roll, 
				_ => throw new InvalidOperationException("Unknown source axis: " + mapping.Source), 
			};
			if (mapping.Invert)
			{
				num = 0f - num;
			}
			return num;
		}

		public static CoordinateTransformer CreateOpenTrackToUnity()
		{
			return new CoordinateTransformer(new AxisMapping(SourceAxis.Yaw, invert: false), new AxisMapping(SourceAxis.Pitch, invert: true), new AxisMapping(SourceAxis.Roll, invert: false));
		}

		public static CoordinateTransformer CreatePassthrough()
		{
			return new CoordinateTransformer();
		}

		public static CoordinateTransformer CreateFromInversions(bool invertYaw, bool invertPitch, bool invertRoll)
		{
			return new CoordinateTransformer(new AxisMapping(SourceAxis.Yaw, invertYaw), new AxisMapping(SourceAxis.Pitch, invertPitch), new AxisMapping(SourceAxis.Roll, invertRoll));
		}
	}
	public enum SourceAxis
	{
		Yaw,
		Pitch,
		Roll
	}
	public struct AxisMapping : IEquatable<AxisMapping>
	{
		public SourceAxis Source { get; }

		public bool Invert { get; }

		public AxisMapping(SourceAxis source, bool invert)
		{
			Source = source;
			Invert = invert;
		}

		public bool Equals(AxisMapping other)
		{
			if (Source == other.Source)
			{
				return Invert == other.Invert;
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			if (obj is AxisMapping)
			{
				return Equals((AxisMapping)obj);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return ((int)Source * 397) ^ Invert.GetHashCode();
		}

		public static bool operator ==(AxisMapping left, AxisMapping right)
		{
			return left.Equals(right);
		}

		public static bool operator !=(AxisMapping left, AxisMapping right)
		{
			return !left.Equals(right);
		}
	}
	public struct DeadzoneSettings : IEquatable<DeadzoneSettings>
	{
		public float Yaw { get; }

		public float Pitch { get; }

		public float Roll { get; }

		public static DeadzoneSettings None => new DeadzoneSettings(0f, 0f, 0f);

		public static DeadzoneSettings Default => new DeadzoneSettings(0.5f, 0.5f, 0.5f);

		public DeadzoneSettings(float yaw, float pitch, float roll)
		{
			Yaw = yaw;
			Pitch = pitch;
			Roll = roll;
		}

		public static DeadzoneSettings Uniform(float deadzone)
		{
			return new DeadzoneSettings(deadzone, deadzone, deadzone);
		}

		public bool Equals(DeadzoneSettings other)
		{
			if (Yaw == other.Yaw && Pitch == other.Pitch)
			{
				return Roll == other.Roll;
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			if (obj is DeadzoneSettings)
			{
				return Equals((DeadzoneSettings)obj);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return ((17 * 31 + Yaw.GetHashCode()) * 31 + Pitch.GetHashCode()) * 31 + Roll.GetHashCode();
		}

		public static bool operator ==(DeadzoneSettings left, DeadzoneSettings right)
		{
			return left.Equals(right);
		}

		public static bool operator !=(DeadzoneSettings left, DeadzoneSettings right)
		{
			return !left.Equals(right);
		}
	}
	public struct PositionData : IEquatable<PositionData>
	{
		public float X { get; }

		public float Y { get; }

		public float Z { get; }

		public long TimestampTicks { get; }

		public bool IsValid => TimestampTicks != 0;

		public static PositionData Zero => new PositionData(0f, 0f, 0f, Stopwatch.GetTimestamp());

		public PositionData(float x, float y, float z, long timestampTicks)
		{
			X = x;
			Y = y;
			Z = z;
			TimestampTicks = timestampTicks;
		}

		public PositionData(float x, float y, float z)
			: this(x, y, z, Stopwatch.GetTimestamp())
		{
		}

		public Vec3 ToVec3()
		{
			return new Vec3(X, Y, Z);
		}

		public PositionData SubtractOffset(PositionData offset)
		{
			return new PositionData(X - offset.X, Y - offset.Y, Z - offset.Z, TimestampTicks);
		}

		public bool Equals(PositionData other)
		{
			if (X == other.X && Y == other.Y)
			{
				return Z == other.Z;
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			if (obj is PositionData)
			{
				return Equals((PositionData)obj);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return ((17 * 31 + X.GetHashCode()) * 31 + Y.GetHashCode()) * 31 + Z.GetHashCode();
		}

		public override string ToString()
		{
			return $"PositionData(X:{X:F4}, Y:{Y:F4}, Z:{Z:F4})";
		}

		public static bool operator ==(PositionData left, PositionData right)
		{
			return left.Equals(right);
		}

		public static bool operator !=(PositionData left, PositionData right)
		{
			return !left.Equals(right);
		}
	}
	public struct PositionSettings
	{
		public float SensitivityX { get; }

		public float SensitivityY { get; }

		public float SensitivityZ { get; }

		public float LimitX { get; }

		public float LimitY { get; }

		public float LimitZ { get; }

		public float LimitZBack { get; }

		public float Smoothing { get; }

		public bool InvertX { get; }

		public bool InvertY { get; }

		public bool InvertZ { get; }

		public static PositionSettings Default => new PositionSettings(1f, 1f, 1f, 0.3f, 0.2f, 0.4f, 0.1f, 0.15f);

		public PositionSettings(float sensitivityX, float sensitivityY, float sensitivityZ, float limitX, float limitY, float limitZ, float limitZBack, float smoothing, bool invertX = false, bool invertY = false, bool invertZ = false)
		{
			SensitivityX = sensitivityX;
			SensitivityY = sensitivityY;
			SensitivityZ = sensitivityZ;
			LimitX = limitX;
			LimitY = limitY;
			LimitZ = limitZ;
			LimitZBack = limitZBack;
			Smoothing = smoothing;
			InvertX = invertX;
			InvertY = invertY;
			InvertZ = invertZ;
		}
	}
	public readonly struct Quat4
	{
		public readonly float X;

		public readonly float Y;

		public readonly float Z;

		public readonly float W;

		public static Quat4 Identity => new Quat4(0f, 0f, 0f, 1f);

		public Quat4 Negated
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				return new Quat4(0f - X, 0f - Y, 0f - Z, 0f - W);
			}
		}

		public Quat4 Inverse
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				return new Quat4(0f - X, 0f - Y, 0f - Z, W);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public Quat4(float x, float y, float z, float w)
		{
			X = x;
			Y = y;
			Z = z;
			W = w;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public float Dot(Quat4 other)
		{
			return X * other.X + Y * other.Y + Z * other.Z + W * other.W;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public Vec3 Rotate(Vec3 v)
		{
			float num = X + X;
			float num2 = Y + Y;
			float num3 = Z + Z;
			float num4 = X * num;
			float num5 = Y * num2;
			float num6 = Z * num3;
			float num7 = X * num2;
			float num8 = X * num3;
			float num9 = Y * num3;
			float num10 = W * num;
			float num11 = W * num2;
			float num12 = W * num3;
			return new Vec3((1f - num5 - num6) * v.X + (num7 - num12) * v.Y + (num8 + num11) * v.Z, (num7 + num12) * v.X + (1f - num4 - num6) * v.Y + (num9 - num10) * v.Z, (num8 - num11) * v.X + (num9 + num10) * v.Y + (1f - num4 - num5) * v.Z);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public Quat4 Multiply(Quat4 b)
		{
			return new Quat4(W * b.X + X * b.W + Y * b.Z - Z * b.Y, W * b.Y - X * b.Z + Y * b.W + Z * b.X, W * b.Z + X * b.Y - Y * b.X + Z * b.W, W * b.W - X * b.X - Y * b.Y - Z * b.Z);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Quat4 operator *(Quat4 a, Quat4 b)
		{
			return a.Multiply(b);
		}
	}
	public struct SensitivitySettings : IEquatable<SensitivitySettings>
	{
		public float Yaw { get; }

		public float Pitch { get; }

		public float Roll { get; }

		public bool InvertYaw { get; }

		public bool InvertPitch { get; }

		public bool InvertRoll { get; }

		public static SensitivitySettings Default => new SensitivitySettings(1f, 1f, 1f);

		public SensitivitySettings(float yaw, float pitch, float roll, bool invertYaw = false, bool invertPitch = false, bool invertRoll = false)
		{
			Yaw = yaw;
			Pitch = pitch;
			Roll = roll;
			InvertYaw = invertYaw;
			InvertPitch = invertPitch;
			InvertRoll = invertRoll;
		}

		public static SensitivitySettings Uniform(float sensitivity)
		{
			return new SensitivitySettings(sensitivity, sensitivity, sensitivity);
		}

		public SensitivitySettings WithYaw(float yaw)
		{
			return new SensitivitySettings(yaw, Pitch, Roll, InvertYaw, InvertPitch, InvertRoll);
		}

		public SensitivitySettings WithPitch(float pitch)
		{
			return new SensitivitySettings(Yaw, pitch, Roll, InvertYaw, InvertPitch, InvertRoll);
		}

		public SensitivitySettings WithRoll(float roll)
		{
			return new SensitivitySettings(Yaw, Pitch, roll, InvertYaw, InvertPitch, InvertRoll);
		}

		public bool Equals(SensitivitySettings other)
		{
			if (Yaw == other.Yaw && Pitch == other.Pitch && Roll == other.Roll && InvertYaw == other.InvertYaw && InvertPitch == other.InvertPitch)
			{
				return InvertRoll == other.InvertRoll;
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			if (obj is SensitivitySettings)
			{
				return Equals((SensitivitySettings)obj);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (((((17 * 31 + Yaw.GetHashCode()) * 31 + Pitch.GetHashCode()) * 31 + Roll.GetHashCode()) * 31 + InvertYaw.GetHashCode()) * 31 + InvertPitch.GetHashCode()) * 31 + InvertRoll.GetHashCode();
		}

		public static bool operator ==(SensitivitySettings left, SensitivitySettings right)
		{
			return left.Equals(right);
		}

		public static bool operator !=(SensitivitySettings left, SensitivitySettings right)
		{
			return !left.Equals(right);
		}
	}
	public struct TrackingPose : IEquatable<TrackingPose>
	{
		public const int DefaultFreshnessMs = 500;

		public float Yaw { get; }

		public float Pitch { get; }

		public float Roll { get; }

		public long TimestampTicks { get; }

		public bool IsValid => TimestampTicks != 0;

		public bool IsDataFresh => IsRecent(500);

		public static TrackingPose Zero => new TrackingPose(0f, 0f, 0f, Stopwatch.GetTimestamp());

		public TrackingPose(float yaw, float pitch, float roll, long timestampTicks)
		{
			Yaw = yaw;
			Pitch = pitch;
			Roll = roll;
			TimestampTicks = timestampTicks;
		}

		public TrackingPose(float yaw, float pitch, float roll)
			: this(yaw, pitch, roll, Stopwatch.GetTimestamp())
		{
		}

		public bool IsRecent(int maxAgeMs)
		{
			if (TimestampTicks == 0L)
			{
				return false;
			}
			return (double)(Stopwatch.GetTimestamp() - TimestampTicks) * 1000.0 / (double)Stopwatch.Frequency < (double)maxAgeMs;
		}

		public TrackingPose SubtractOffset(TrackingPose offset)
		{
			return new TrackingPose(Yaw - offset.Yaw, Pitch - offset.Pitch, Roll - offset.Roll, TimestampTicks);
		}

		public TrackingPose ApplySensitivity(SensitivitySettings sensitivity)
		{
			float num = Yaw * sensitivity.Yaw;
			float num2 = Pitch * sensitivity.Pitch;
			float num3 = Roll * sensitivity.Roll;
			if (sensitivity.InvertYaw)
			{
				num = 0f - num;
			}
			if (sensitivity.InvertPitch)
			{
				num2 = 0f - num2;
			}
			if (sensitivity.InvertRoll)
			{
				num3 = 0f - num3;
			}
			return new TrackingPose(num, num2, num3, TimestampTicks);
		}

		public bool Equals(TrackingPose other)
		{
			if (Yaw == other.Yaw && Pitch == other.Pitch)
			{
				return Roll == other.Roll;
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			if (obj is TrackingPose)
			{
				return Equals((TrackingPose)obj);
			}
			return false;
		}

		public override int GetHashCode()
		{
			return ((17 * 31 + Yaw.GetHashCode()) * 31 + Pitch.GetHashCode()) * 31 + Roll.GetHashCode();
		}

		public override string ToString()
		{
			return $"TrackingPose(Y:{Yaw:F2}, P:{Pitch:F2}, R:{Roll:F2})";
		}

		public static bool operator ==(TrackingPose left, TrackingPose right)
		{
			return left.Equals(right);
		}

		public static bool operator !=(TrackingPose left, TrackingPose right)
		{
			return !left.Equals(right);
		}
	}
	public readonly struct Vec3
	{
		public readonly float X;

		public readonly float Y;

		public readonly float Z;

		public static Vec3 Zero => new Vec3(0f, 0f, 0f);

		public static Vec3 Forward => new Vec3(0f, 0f, 1f);

		public static Vec3 Up => new Vec3(0f, 1f, 0f);

		public static Vec3 Right => new Vec3(1f, 0f, 0f);

		public float SqrMagnitude
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				return X * X + Y * Y + Z * Z;
			}
		}

		public float Magnitude
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				return (float)System.Math.Sqrt(X * X + Y * Y + Z * Z);
			}
		}

		public Vec3 Normalized
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				float num = X * X + Y * Y + Z * Z;
				if (num < 1E-08f)
				{
					return Zero;
				}
				float num2 = 1f / (float)System.Math.Sqrt(num);
				return new Vec3(X * num2, Y * num2, Z * num2);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public Vec3(float x, float y, float z)
		{
			X = x;
			Y = y;
			Z = z;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Vec3 operator +(Vec3 a, Vec3 b)
		{
			return new Vec3(a.X + b.X, a.Y + b.Y, a.Z + b.Z);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Vec3 operator -(Vec3 a, Vec3 b)
		{
			return new Vec3(a.X - b.X, a.Y - b.Y, a.Z - b.Z);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Vec3 operator *(Vec3 v, float s)
		{
			return new Vec3(v.X * s, v.Y * s, v.Z * s);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Vec3 operator *(float s, Vec3 v)
		{
			return new Vec3(v.X * s, v.Y * s, v.Z * s);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Vec3 operator -(Vec3 v)
		{
			return new Vec3(0f - v.X, 0f - v.Y, 0f - v.Z);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static float Dot(Vec3 a, Vec3 b)
		{
			return a.X * b.X + a.Y * b.Y + a.Z * b.Z;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Vec3 Lerp(Vec3 a, Vec3 b, float t)
		{
			return new Vec3(a.X + (b.X - a.X) * t, a.Y + (b.Y - a.Y) * t, a.Z + (b.Z - a.Z) * t);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static Vec3 Cross(Vec3 a, Vec3 b)
		{
			return new Vec3(a.Y * b.Z - a.Z * b.Y, a.Z * b.X - a.X * b.Z, a.X * b.Y - a.Y * b.X);
		}

		public override string ToString()
		{
			return $"({X:F3}, {Y:F3}, {Z:F3})";
		}
	}
}
namespace CameraUnlock.Core.Config
{
	public static class ConfigParsingUtils
	{
		public static bool TryParseColor(string value, out float[] rgba)
		{
			rgba = new float[4] { 1f, 1f, 1f, 1f };
			if (string.IsNullOrEmpty(value))
			{
				return false;
			}
			string[] array = value.Split(new char[1] { ',' });
			if (array.Length < 3)
			{
				return false;
			}
			float result = 1f;
			if (!TryParseFloat(array[0], out var result2) || !TryParseFloat(array[1], out var result3) || !TryParseFloat(array[2], out var result4))
			{
				return false;
			}
			if (array.Length >= 4 && !TryParseFloat(array[3], out result))
			{
				result = 1f;
			}
			if (result2 > 1f || result3 > 1f || result4 > 1f || result > 1f)
			{
				result2 /= 255f;
				result3 /= 255f;
				result4 /= 255f;
				if (result > 1f)
				{
					result /= 255f;
				}
			}
			rgba[0] = MathUtils.Clamp01(result2);
			rgba[1] = MathUtils.Clamp01(result3);
			rgba[2] = MathUtils.Clamp01(result4);
			rgba[3] = MathUtils.Clamp01(result);
			return true;
		}

		public static bool TryParseFloat(string value, out float result)
		{
			if (string.IsNullOrEmpty(value))
			{
				result = 0f;
				return false;
			}
			return float.TryParse(value.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out result);
		}

		public static bool TryParseInt(string value, out int result)
		{
			if (string.IsNullOrEmpty(value))
			{
				result = 0;
				return false;
			}
			return int.TryParse(value.Trim(), out result);
		}

		public static bool TryParseBool(string value, out bool result)
		{
			result = false;
			if (string.IsNullOrEmpty(value))
			{
				return false;
			}
			switch (value.Trim().ToLowerInvariant())
			{
			case "true":
			case "yes":
			case "1":
				result = true;
				return true;
			case "false":
			case "no":
			case "0":
				result = false;
				return true;
			default:
				return false;
			}
		}

		public static Dictionary<string, string> ParseIniFile(string filePath)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
			if (!File.Exists(filePath))
			{
				return dictionary;
			}
			string[] array = File.ReadAllLines(filePath);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (string.IsNullOrEmpty(text) || text.StartsWith("#") || text.StartsWith(";") || text.StartsWith("["))
				{
					continue;
				}
				int num = text.IndexOf('=');
				if (num > 0)
				{
					string key = text.Substring(0, num).Trim();
					string text2 = text.Substring(num + 1).Trim();
					if (text2.Length >= 2 && ((text2.StartsWith("\"") && text2.EndsWith("\"")) || (text2.StartsWith("'") && text2.EndsWith("'"))))
					{
						text2 = text2.Substring(1, text2.Length - 2);
					}
					dictionary[key] = text2;
				}
			}
			return dictionary;
		}

		public static string GetAssemblyDirectory(Assembly assembly)
		{
			if ((object)assembly == null)
			{
				return string.Empty;
			}
			string location = assembly.Location;
			if (string.IsNullOrEmpty(location))
			{
				return string.Empty;
			}
			return Path.GetDirectoryName(location) ?? string.Empty;
		}
	}
	public class HeadTrackingConfigData : IHeadTrackingConfig
	{
		public int UdpPort { get; set; } = 4242;


		public bool EnableOnStartup { get; set; } = true;


		public SensitivitySettings Sensitivity { get; set; } = SensitivitySettings.Default;


		public string RecenterKeyName { get; set; } = "Home";


		public string ToggleKeyName { get; set; } = "End";


		public bool AimDecouplingEnabled { get; set; } = true;


		public bool ShowDecoupledReticle { get; set; } = true;


		public float[] ReticleColorRgba { get; set; } = new float[4] { 1f, 1f, 1f, 1f };


		public float Smoothing { get; set; }

		public static HeadTrackingConfigData LoadFromFile(string filePath, Action<string> log = null)
		{
			HeadTrackingConfigData headTrackingConfigData = new HeadTrackingConfigData();
			try
			{
				Dictionary<string, string> dictionary = ConfigParsingUtils.ParseIniFile(filePath);
				if (dictionary.Count == 0)
				{
					log?.Invoke("No config file found, using defaults");
					return headTrackingConfigData;
				}
				headTrackingConfigData.ApplyValues(dictionary, log);
				log?.Invoke("Config loaded successfully");
			}
			catch (Exception ex)
			{
				log?.Invoke($"Config load error (using defaults): {ex.Message}");
			}
			return headTrackingConfigData;
		}

		public void ApplyValues(Dictionary<string, string> values, Action<string> log = null)
		{
			float yaw = Sensitivity.Yaw;
			float pitch = Sensitivity.Pitch;
			float roll = Sensitivity.Roll;
			bool invertYaw = Sensitivity.InvertYaw;
			bool invertPitch = Sensitivity.InvertPitch;
			bool invertRoll = Sensitivity.InvertRoll;
			foreach (KeyValuePair<string, string> value2 in values)
			{
				string text = value2.Key.ToLowerInvariant().Replace("_", "").Replace("-", "");
				string value = value2.Value;
				bool result2;
				float result;
				switch (text)
				{
				case "udpport":
				case "port":
				{
					if (ConfigParsingUtils.TryParseInt(value, out var result3))
					{
						UdpPort = result3;
					}
					break;
				}
				case "enabled":
				case "enableonstartup":
					if (ConfigParsingUtils.TryParseBool(value, out result2))
					{
						EnableOnStartup = result2;
					}
					break;
				case "yawsens":
				case "yawsensitivity":
					if (ConfigParsingUtils.TryParseFloat(value, out result))
					{
						yaw = result;
					}
					break;
				case "pitchsens":
				case "pitchsensitivity":
					if (ConfigParsingUtils.TryParseFloat(value, out result))
					{
						pitch = result;
					}
					break;
				case "rollsensitivity":
				case "rollsens":
					if (ConfigParsingUtils.TryParseFloat(value, out result))
					{
						roll = result;
					}
					break;
				case "invertyaw":
					if (ConfigParsingUtils.TryParseBool(value, out result2))
					{
						invertYaw = result2;
					}
					break;
				case "invertpitch":
					if (ConfigParsingUtils.TryParseBool(value, out result2))
					{
						invertPitch = result2;
					}
					break;
				case "invertroll":
					if (ConfigParsingUtils.TryParseBool(value, out result2))
					{
						invertRoll = result2;
					}
					break;
				case "centerkey":
				case "recenterkey":
					RecenterKeyName = value;
					break;
				case "togglekey":
					ToggleKeyName = value;
					break;
				case "aimdecouple":
				case "decoupleaim":
				case "aimdecoupling":
					if (ConfigParsingUtils.TryParseBool(value, out result2))
					{
						AimDecouplingEnabled = result2;
					}
					break;
				case "showreticle":
				case "showcrosshair":
				case "showdecoupledreticle":
					if (ConfigParsingUtils.TryParseBool(value, out result2))
					{
						ShowDecoupledReticle = result2;
					}
					break;
				case "crosshaircolor":
				case "reticlecolor":
				{
					if (ConfigParsingUtils.TryParseColor(value, out var rgba))
					{
						ReticleColorRgba = rgba;
					}
					break;
				}
				case "smoothing":
					if (ConfigParsingUtils.TryParseFloat(value, out result))
					{
						Smoothing = System.Math.Max(0f, System.Math.Min(1f, result));
					}
					break;
				}
			}
			Sensitivity = new SensitivitySettings(yaw, pitch, roll, invertYaw, invertPitch, invertRoll);
		}

		public static string GetDefaultConfigPath(Assembly assembly, string fileName = "HeadTracking.cfg")
		{
			return Path.Combine(ConfigParsingUtils.GetAssemblyDirectory(assembly), fileName);
		}
	}
	public interface IConfigChangeNotifier
	{
		event EventHandler ConfigChanged;
	}
	public interface INotifyingHeadTrackingConfig : IHeadTrackingConfig, IConfigChangeNotifier
	{
	}
	public interface IHeadTrackingConfig
	{
		int UdpPort { get; }

		bool EnableOnStartup { get; }

		SensitivitySettings Sensitivity { get; }

		string RecenterKeyName { get; }

		string ToggleKeyName { get; }

		bool AimDecouplingEnabled { get; }

		bool ShowDecoupledReticle { get; }

		float[] ReticleColorRgba { get; }

		float Smoothing { get; }
	}
}
namespace CameraUnlock.Core.Config.Profiles
{
	public class ConfigProfile
	{
		public string Name { get; set; }

		public string Description { get; set; }

		public string GameName { get; set; }

		public DateTime CreatedDate { get; set; }

		public DateTime ModifiedDate { get; set; }

		public bool IsDefault { get; set; }

		public bool IsReadOnly { get; set; }

		public Dictionary<string, object> Settings { get; set; }

		public MappingConfig AxisMapping { get; set; }

		public ConfigProfile()
		{
			Name = "New Profile";
			Description = "";
			GameName = "General";
			CreatedDate = DateTime.Now;
			ModifiedDate = DateTime.Now;
			Settings = new Dictionary<string, object>();
			AxisMapping = new MappingConfig();
		}

		public ConfigProfile(string name)
			: this()
		{
			Name = name;
		}

		public ConfigProfile(string name, string description, string gameName = "General")
			: this()
		{
			Name = name;
			Description = description;
			GameName = gameName;
		}

		public void ExportFromAdapter(IProfileSettings adapter)
		{
			if (adapter == null)
			{
				throw new ArgumentNullException("adapter");
			}
			Settings = adapter.ExportSettings();
			GameName = adapter.GameName;
			ModifiedDate = DateTime.Now;
		}

		public void ImportToAdapter(IProfileSettings adapter)
		{
			if (adapter == null)
			{
				throw new ArgumentNullException("adapter");
			}
			adapter.ImportSettings(Settings);
			adapter.SaveConfig();
		}

		public ConfigProfile Clone(string newName)
		{
			if (string.IsNullOrEmpty(newName))
			{
				throw new ArgumentException("New name cannot be null or empty", "newName");
			}
			return new ConfigProfile
			{
				Name = newName,
				Description = Description + " (Copy)",
				GameName = GameName,
				CreatedDate = DateTime.Now,
				ModifiedDate = DateTime.Now,
				IsDefault = false,
				IsReadOnly = false,
				Settings = new Dictionary<string, object>(Settings),
				AxisMapping = (AxisMapping?.Clone() ?? new MappingConfig())
			};
		}

		public T GetSetting<T>(string key, T defaultValue = default(T))
		{
			if (Settings == null || !Settings.TryGetValue(key, out var value))
			{
				return defaultValue;
			}
			if (value is T)
			{
				return (T)value;
			}
			return (T)Convert.ChangeType(value, typeof(T));
		}

		public void SetSetting(string key, object value)
		{
			if (Settings == null)
			{
				Settings = new Dictionary<string, object>();
			}
			Settings[key] = value;
			ModifiedDate = DateTime.Now;
		}
	}
	public interface IProfileSettings
	{
		string GameName { get; }

		Dictionary<string, object> ExportSettings();

		void ImportSettings(Dictionary<string, object> settings);

		void SaveConfig();
	}
	public class ProfileManager
	{
		private readonly string _profilesDirectory;

		private readonly Dictionary<string, ConfigProfile> _profiles;

		private ConfigProfile _activeProfile;

		private string _activeProfileName;

		public const string ProfileExtension = ".profile";

		public string ProfilesDirectory => _profilesDirectory;

		public ConfigProfile ActiveProfile => _activeProfile;

		public string ActiveProfileName => _activeProfileName;

		public IDictionary<string, ConfigProfile> Profiles => _profiles;

		public event Action<string> ProfileChanged;

		public ProfileManager(string profilesDirectory)
		{
			if (string.IsNullOrEmpty(profilesDirectory))
			{
				throw new ArgumentException("Profiles directory cannot be null or empty", "profilesDirectory");
			}
			_profilesDirectory = profilesDirectory;
			_profiles = new Dictionary<string, ConfigProfile>(StringComparer.OrdinalIgnoreCase);
			if (!Directory.Exists(_profilesDirectory))
			{
				Directory.CreateDirectory(_profilesDirectory);
			}
			LoadAllProfiles();
			if (_profiles.Count == 0)
			{
				CreateDefaultProfiles();
			}
		}

		public void LoadAllProfiles()
		{
			_profiles.Clear();
			if (Directory.Exists(_profilesDirectory))
			{
				string[] files = Directory.GetFiles(_profilesDirectory, "*.profile");
				foreach (string obj in files)
				{
					string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(obj);
					ConfigProfile value = ProfileSerializer.ReadFromFile(obj);
					_profiles[fileNameWithoutExtension] = value;
				}
			}
		}

		public void CreateDefaultProfiles()
		{
			ConfigProfile configProfile = new ConfigProfile("Default", "Default configuration for most games")
			{
				IsDefault = true
			};
			configProfile.AxisMapping.ResetToDefault();
			_profiles["Default"] = configProfile;
			SaveProfile(configProfile);
			ConfigProfile configProfile2 = new ConfigProfile("FPS_Competitive", "Optimized for competitive FPS games", "FPS");
			configProfile2.AxisMapping.LoadPreset(MappingPreset.Competitive);
			_profiles["FPS_Competitive"] = configProfile2;
			SaveProfile(configProfile2);
			ConfigProfile configProfile3 = new ConfigProfile("Simulation", "Realistic head movement for simulation games", "Simulation");
			configProfile3.AxisMapping.LoadPreset(MappingPreset.Simulation);
			_profiles["Simulation"] = configProfile3;
			SaveProfile(configProfile3);
		}

		public void LoadProfile(string profileName)
		{
			if (!_profiles.TryGetValue(profileName, out var value))
			{
				throw new KeyNotFoundException("Profile not found: " + profileName);
			}
			_activeProfile = value;
			_activeProfileName = profileName;
			this.ProfileChanged?.Invoke(profileName);
		}

		public void SaveProfile(ConfigProfile profile)
		{
			if (profile == null)
			{
				throw new ArgumentNullException("profile");
			}
			if (profile.IsReadOnly)
			{
				throw new InvalidOperationException("Cannot save read-only profile: " + profile.Name);
			}
			profile.ModifiedDate = DateTime.Now;
			string profilePath = GetProfilePath(profile.Name);
			ProfileSerializer.WriteToFile(profile, profilePath);
			_profiles[profile.Name] = profile;
		}

		public ConfigProfile CreateProfile(string name, string description, string gameName = "General")
		{
			if (_profiles.ContainsKey(name))
			{
				throw new InvalidOperationException("Profile already exists: " + name);
			}
			ConfigProfile configProfile = new ConfigProfile(name, description, gameName);
			configProfile.AxisMapping.ResetToDefault();
			_profiles[name] = configProfile;
			SaveProfile(configProfile);
			return configProfile;
		}

		public void DeleteProfile(string profileName)
		{
			if (!_profiles.TryGetValue(profileName, out var value))
			{
				throw new KeyNotFoundException("Profile not found: " + profileName);
			}
			if (value.IsReadOnly || value.IsDefault)
			{
				throw new InvalidOperationException("Cannot delete protected profile: " + profileName);
			}
			_profiles.Remove(profileName);
			string profilePath = GetProfilePath(profileName);
			if (File.Exists(profilePath))
			{
				File.Delete(profilePath);
			}
			if (_activeProfileName != null && _activeProfileName.Equals(profileName, StringComparison.OrdinalIgnoreCase))
			{
				if (_profiles.ContainsKey("Default"))
				{
					LoadProfile("Default");
					return;
				}
				if (_profiles.Count > 0)
				{
					LoadProfile(_profiles.Keys.First());
					return;
				}
				_activeProfile = null;
				_activeProfileName = null;
			}
		}

		public ConfigProfile DuplicateProfile(string sourceName, string newName)
		{
			if (!_profiles.TryGetValue(sourceName, out var value))
			{
				throw new KeyNotFoundException("Source profile not found: " + sourceName);
			}
			if (_profiles.ContainsKey(newName))
			{
				throw new InvalidOperationException("Profile already exists: " + newName);
			}
			ConfigProfile configProfile = value.Clone(newName);
			configProfile.IsDefault = false;
			configProfile.IsReadOnly = false;
			_profiles[newName] = configProfile;
			SaveProfile(configProfile);
			return configProfile;
		}

		public List<string> GetProfileNames()
		{
			List<string> list = _profiles.Keys.ToList();
			list.Sort(StringComparer.OrdinalIgnoreCase);
			return list;
		}

		public ConfigProfile GetProfile(string name)
		{
			_profiles.TryGetValue(name, out var value);
			return value;
		}

		public bool ProfileExists(string name)
		{
			return _profiles.ContainsKey(name);
		}

		public void SaveCurrentToActiveProfile(IProfileSettings adapter)
		{
			if (_activeProfile == null)
			{
				throw new InvalidOperationException("No active profile");
			}
			if (_activeProfile.IsReadOnly)
			{
				throw new InvalidOperationException("Cannot save to read-only profile");
			}
			_activeProfile.ExportFromAdapter(adapter);
			SaveProfile(_activeProfile);
		}

		public void ApplyActiveProfileToConfig(IProfileSettings adapter)
		{
			if (_activeProfile == null)
			{
				throw new InvalidOperationException("No active profile");
			}
			_activeProfile.ImportToAdapter(adapter);
		}

		private string GetProfilePath(string profileName)
		{
			return Path.Combine(_profilesDirectory, profileName + ".profile");
		}
	}
	public static class ProfileSerializer
	{
		private const string FileHeader = "# CameraUnlock Configuration Profile";

		private const string DateFormat = "yyyy-MM-dd HH:mm:ss";

		private static bool IsNullOrWhiteSpace(string value)
		{
			if (value == null)
			{
				return true;
			}
			for (int i = 0; i < value.Length; i++)
			{
				if (!char.IsWhiteSpace(value[i]))
				{
					return false;
				}
			}
			return true;
		}

		private static bool TryParseEnum<T>(string value, out T result) where T : struct
		{
			result = default(T);
			if (string.IsNullOrEmpty(value))
			{
				return false;
			}
			try
			{
				result = (T)Enum.Parse(typeof(T), value, ignoreCase: true);
				return true;
			}
			catch (ArgumentException)
			{
				return false;
			}
		}

		public static string Serialize(ConfigProfile profile)
		{
			if (profile == null)
			{
				throw new ArgumentNullException("profile");
			}
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("# CameraUnlock Configuration Profile");
			stringBuilder.AppendLine("# Generated: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture));
			stringBuilder.AppendLine();
			stringBuilder.AppendLine("Name=" + profile.Name);
			stringBuilder.AppendLine("Description=" + profile.Description);
			stringBuilder.AppendLine("GameName=" + (profile.GameName ?? "General"));
			stringBuilder.AppendLine("CreatedDate=" + profile.CreatedDate.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture));
			stringBuilder.AppendLine("ModifiedDate=" + profile.ModifiedDate.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture));
			stringBuilder.AppendLine("IsDefault=" + profile.IsDefault);
			stringBuilder.AppendLine("IsReadOnly=" + profile.IsReadOnly);
			stringBuilder.AppendLine();
			if (profile.Settings != null && profile.Settings.Count > 0)
			{
				stringBuilder.AppendLine("# Configuration Settings");
				foreach (KeyValuePair<string, object> setting in profile.Settings)
				{
					string text = SerializeValue(setting.Value);
					stringBuilder.AppendLine("Setting." + setting.Key + "=" + text);
				}
				stringBuilder.AppendLine();
			}
			if (profile.AxisMapping != null)
			{
				stringBuilder.AppendLine("# Axis Mapping Configuration");
				SerializeAxisConfig(stringBuilder, "Yaw", profile.AxisMapping.YawConfig);
				SerializeAxisConfig(stringBuilder, "Pitch", profile.AxisMapping.PitchConfig);
				SerializeAxisConfig(stringBuilder, "Roll", profile.AxisMapping.RollConfig);
			}
			return stringBuilder.ToString();
		}

		public static void WriteToFile(ConfigProfile profile, string filePath)
		{
			if (profile == null)
			{
				throw new ArgumentNullException("profile");
			}
			if (string.IsNullOrEmpty(filePath))
			{
				throw new ArgumentNullException("filePath");
			}
			string contents = Serialize(profile);
			File.WriteAllText(filePath, contents, Encoding.UTF8);
		}

		public static ConfigProfile Deserialize(string content)
		{
			if (content == null)
			{
				throw new ArgumentNullException("content");
			}
			ConfigProfile configProfile = new ConfigProfile();
			string[] array = content.Split(new char[2] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
			foreach (string text in array)
			{
				if (!IsNullOrWhiteSpace(text) && !text.StartsWith("#"))
				{
					int num = text.IndexOf('=');
					if (num >= 0)
					{
						string key = text.Substring(0, num).Trim();
						string value = text.Substring(num + 1).Trim();
						ParseLine(configProfile, key, value);
					}
				}
			}
			return configProfile;
		}

		public static ConfigProfile ReadFromFile(string filePath)
		{
			if (string.IsNullOrEmpty(filePath))
			{
				throw new ArgumentNullException("filePath");
			}
			if (!File.Exists(filePath))
			{
				throw new FileNotFoundException("Profile file not found", filePath);
			}
			return Deserialize(File.ReadAllText(filePath, Encoding.UTF8));
		}

		private static void SerializeAxisConfig(StringBuilder sb, string axisName, AxisConfig config)
		{
			if (config != null)
			{
				string text = "AxisMapping." + axisName + ".";
				sb.AppendLine(text + "Source=" + config.Source);
				sb.AppendLine(text + "Sensitivity=" + config.Sensitivity.ToString("F4", CultureInfo.InvariantCulture));
				sb.AppendLine(text + "Inverted=" + config.Inverted);
				sb.AppendLine(text + "DeadzoneMin=" + config.DeadzoneMin.ToString("F4", CultureInfo.InvariantCulture));
				sb.AppendLine(text + "DeadzoneMax=" + config.DeadzoneMax.ToString("F4", CultureInfo.InvariantCulture));
				sb.AppendLine(text + "MinLimit=" + config.MinLimit.ToString("F4", CultureInfo.InvariantCulture));
				sb.AppendLine(text + "MaxLimit=" + config.MaxLimit.ToString("F4", CultureInfo.InvariantCulture));
				sb.AppendLine(text + "EnableLimits=" + config.EnableLimits);
				sb.AppendLine(text + "SensitivityCurve=" + config.SensitivityCurve);
				sb.AppendLine(text + "CurveStrength=" + config.CurveStrength.ToString("F4", CultureInfo.InvariantCulture));
			}
		}

		private static string SerializeValue(object value)
		{
			if (value == null)
			{
				return "";
			}
			if (value is float num)
			{
				return num.ToString("F6", CultureInfo.InvariantCulture);
			}
			if (value is double num2)
			{
				return num2.ToString("F6", CultureInfo.InvariantCulture);
			}
			if (value is bool flag)
			{
				return flag.ToString();
			}
			if (value is Enum @enum)
			{
				return @enum.ToString();
			}
			return value.ToString();
		}

		private static void ParseLine(ConfigProfile profile, string key, string value)
		{
			switch (key)
			{
			case "Name":
				profile.Name = value;
				return;
			case "Description":
				profile.Description = value;
				return;
			case "GameName":
				profile.GameName = value;
				return;
			case "CreatedDate":
			{
				if (DateTime.TryParseExact(value, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out var result2))
				{
					profile.CreatedDate = result2;
				}
				return;
			}
			case "ModifiedDate":
			{
				if (DateTime.TryParseExact(value, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out var result))
				{
					profile.ModifiedDate = result;
				}
				return;
			}
			case "IsDefault":
			{
				if (bool.TryParse(value, out var result4))
				{
					profile.IsDefault = result4;
				}
				return;
			}
			case "IsReadOnly":
			{
				if (bool.TryParse(value, out var result3))
				{
					profile.IsReadOnly = result3;
				}
				return;
			}
			}
			if (key.StartsWith("Setting."))
			{
				string key2 = key.Substring(8);
				profile.Settings[key2] = ParseValue(value);
			}
			else if (key.StartsWith("AxisMapping."))
			{
				ParseAxisMapping(profile, key.Substring(12), value);
			}
		}

		private static object ParseValue(string value)
		{
			if (bool.TryParse(value, out var result))
			{
				return result;
			}
			if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2))
			{
				return result2;
			}
			if (float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result3))
			{
				return result3;
			}
			return value;
		}

		private static void ParseAxisMapping(ConfigProfile profile, string key, string value)
		{
			if (profile.AxisMapping == null)
			{
				profile.AxisMapping = new MappingConfig();
			}
			string[] array = key.Split(new char[1] { '.' });
			if (array.Length < 2)
			{
				return;
			}
			AxisConfig axisConfig;
			switch (array[0])
			{
			default:
				return;
			case "Yaw":
				axisConfig = profile.AxisMapping.YawConfig;
				break;
			case "Pitch":
				axisConfig = profile.AxisMapping.PitchConfig;
				break;
			case "Roll":
				axisConfig = profile.AxisMapping.RollConfig;
				break;
			}
			string text = array[1];
			if (text == null)
			{
				return;
			}
			float result;
			bool result2;
			switch (text.Length)
			{
			case 11:
				switch (text[9])
				{
				case 't':
					if (text == "Sensitivity" && float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out result))
					{
						axisConfig.Sensitivity = result;
					}
					break;
				case 'i':
					if (text == "DeadzoneMin" && float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out result))
					{
						axisConfig.DeadzoneMin = result;
					}
					break;
				case 'a':
					if (text == "DeadzoneMax" && float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out result))
					{
						axisConfig.DeadzoneMax = result;
					}
					break;
				}
				break;
			case 8:
				switch (text[1])
				{
				case 'n':
					if (text == "Inverted" && bool.TryParse(value, out result2))
					{
						axisConfig.Inverted = result2;
					}
					break;
				case 'i':
					if (text == "MinLimit" && float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out result))
					{
						axisConfig.MinLimit = result;
					}
					break;
				case 'a':
					if (text == "MaxLimit" && float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out result))
					{
						axisConfig.MaxLimit = result;
					}
					break;
				}
				break;
			case 6:
			{
				if (text == "Source" && TryParseEnum<AxisSource>(va

plugins\CameraUnlock.Core.Unity.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using CameraUnlock.Core.Aim;
using CameraUnlock.Core.Data;
using CameraUnlock.Core.Input;
using CameraUnlock.Core.Math;
using CameraUnlock.Core.Processing;
using CameraUnlock.Core.Unity.Extensions;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("CameraUnlock Mods")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Unity-specific extensions for CameraUnlock head tracking mods")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1+ffa50e702c2238550a17fde0fc8b3e63da95026c")]
[assembly: AssemblyProduct("CameraUnlock.Core.Unity")]
[assembly: AssemblyTitle("CameraUnlock.Core.Unity")]
[assembly: AssemblyVersion("1.0.1.0")]
namespace CameraUnlock.Core.Unity.Utilities
{
	public static class CrosshairUtility
	{
		public static List<Image> FindCrosshairCandidates(bool searchInactive = true)
		{
			List<Image> list = new List<Image>();
			Image[] array = (searchInactive ? Resources.FindObjectsOfTypeAll<Image>() : Object.FindObjectsOfType<Image>());
			foreach (Image val in array)
			{
				if (!((Object)(object)val == (Object)null))
				{
					string text = ((Object)val).name.ToLowerInvariant();
					string text2 = ((Object)((Component)val).gameObject).name.ToLowerInvariant();
					if (text.Contains("crosshair") || text.Contains("reticle") || text.Contains("reticule") || text.Contains("aim") || text2.Contains("crosshair") || text2.Contains("reticle") || text2.Contains("reticule"))
					{
						list.Add(val);
					}
				}
			}
			return list;
		}

		public static List<RawImage> FindRawImageCrosshairCandidates(bool searchInactive = true)
		{
			List<RawImage> list = new List<RawImage>();
			RawImage[] array = (searchInactive ? Resources.FindObjectsOfTypeAll<RawImage>() : Object.FindObjectsOfType<RawImage>());
			foreach (RawImage val in array)
			{
				if (!((Object)(object)val == (Object)null))
				{
					string text = ((Object)val).name.ToLowerInvariant();
					string text2 = ((Object)((Component)val).gameObject).name.ToLowerInvariant();
					if (text.Contains("crosshair") || text.Contains("reticle") || text.Contains("reticule") || text.Contains("aim") || text2.Contains("crosshair") || text2.Contains("reticle") || text2.Contains("reticule"))
					{
						list.Add(val);
					}
				}
			}
			return list;
		}

		public static Type FindTypeByName(string typeName)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				try
				{
					Type type = assembly.GetType(typeName);
					if (type != null)
					{
						return type;
					}
				}
				catch (ReflectionTypeLoadException)
				{
				}
				catch (FileNotFoundException)
				{
				}
			}
			return null;
		}

		public static void OffsetByScreenPixels(RectTransform rectTransform, Vector2 screenOffset)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)rectTransform == (Object)null))
			{
				Vector3 lossyScale = ((Transform)rectTransform).lossyScale;
				float num = ((lossyScale.x > 0.001f) ? lossyScale.x : 1f);
				float num2 = ((lossyScale.y > 0.001f) ? lossyScale.y : 1f);
				rectTransform.anchoredPosition = new Vector2(screenOffset.x / num, screenOffset.y / num2);
			}
		}

		public static bool HideGraphic(Graphic graphic)
		{
			if ((Object)(object)graphic == (Object)null || (Object)(object)((Component)graphic).gameObject == (Object)null)
			{
				return false;
			}
			bool activeSelf = ((Component)graphic).gameObject.activeSelf;
			((Component)graphic).gameObject.SetActive(false);
			return activeSelf;
		}

		public static void ShowGraphic(Graphic graphic, bool active = true)
		{
			if (!((Object)(object)graphic == (Object)null) && !((Object)(object)((Component)graphic).gameObject == (Object)null))
			{
				((Component)graphic).gameObject.SetActive(active);
			}
		}

		public static float GetCanvasScaleFactor(Graphic graphic)
		{
			if ((Object)(object)graphic == (Object)null)
			{
				return 1f;
			}
			Canvas componentInParent = ((Component)graphic).GetComponentInParent<Canvas>();
			if (!((Object)(object)componentInParent != (Object)null))
			{
				return 1f;
			}
			return componentInParent.scaleFactor;
		}
	}
	public static class GameUIFinder
	{
		public static readonly string[] CommonReticleNames = new string[15]
		{
			"Reticle", "reticle", "CrossHair", "Crosshair", "crosshair", "Cursor", "cursor", "AimIndicator", "CenterDot", "HUD_Reticle",
			"UIReticle", "InteractionCursor", "LookCursor", "Dot", "dot"
		};

		public static readonly string[] ReticleKeywords = new string[5] { "reticle", "crosshair", "aimpoint", "centerdot", "cursor" };

		public static GameObject FindByNames(params string[] names)
		{
			if (names == null)
			{
				return null;
			}
			foreach (string text in names)
			{
				if (!string.IsNullOrEmpty(text))
				{
					GameObject val = GameObject.Find(text);
					if ((Object)(object)val != (Object)null)
					{
						return val;
					}
				}
			}
			return null;
		}

		public static GameObject FindByKeywords(params string[] keywords)
		{
			if (keywords == null || keywords.Length == 0)
			{
				return null;
			}
			GameObject[] array = Object.FindObjectsOfType<GameObject>();
			foreach (GameObject val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				string text = ((Object)val).name.ToLowerInvariant();
				foreach (string text2 in keywords)
				{
					if (!string.IsNullOrEmpty(text2) && text.Contains(text2.ToLowerInvariant()))
					{
						return val;
					}
				}
			}
			return null;
		}

		public static GameObject FindInCanvas(params string[] keywords)
		{
			if (keywords == null || keywords.Length == 0)
			{
				return null;
			}
			Type type = Type.GetType("UnityEngine.Canvas, UnityEngine") ?? Type.GetType("UnityEngine.Canvas, UnityEngine.UIModule");
			if (type == null)
			{
				return null;
			}
			Object[] array = Object.FindObjectsOfType(type);
			foreach (Object obj in array)
			{
				Component val = (Component)(object)((obj is Component) ? obj : null);
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Transform[] componentsInChildren = val.GetComponentsInChildren<Transform>(true);
				foreach (Transform val2 in componentsInChildren)
				{
					if ((Object)(object)val2 == (Object)null)
					{
						continue;
					}
					string text = ((Object)val2).name.ToLowerInvariant();
					foreach (string text2 in keywords)
					{
						if (!string.IsNullOrEmpty(text2) && text.Contains(text2.ToLowerInvariant()))
						{
							return ((Component)val2).gameObject;
						}
					}
				}
			}
			return null;
		}

		public static GameObject FindReticle(string[] customNames = null)
		{
			if (customNames != null && customNames.Length != 0)
			{
				GameObject val = FindByNames(customNames);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			GameObject val2 = FindByNames(CommonReticleNames);
			if ((Object)(object)val2 != (Object)null)
			{
				return val2;
			}
			val2 = FindByKeywords(ReticleKeywords);
			if ((Object)(object)val2 != (Object)null)
			{
				return val2;
			}
			return FindInCanvas(ReticleKeywords);
		}

		public static RectTransform GetRectTransform(GameObject gameObject)
		{
			if ((Object)(object)gameObject == (Object)null)
			{
				return null;
			}
			return gameObject.GetComponent<RectTransform>();
		}

		public static GameObject FindByPath(string rootName, string path)
		{
			if (string.IsNullOrEmpty(rootName) && string.IsNullOrEmpty(path))
			{
				return null;
			}
			GameObject val = null;
			if (!string.IsNullOrEmpty(rootName))
			{
				val = GameObject.Find(rootName);
				if ((Object)(object)val == (Object)null)
				{
					return null;
				}
			}
			if (string.IsNullOrEmpty(path))
			{
				return val;
			}
			if ((Object)(object)val == (Object)null)
			{
				return GameObject.Find(path);
			}
			Transform val2 = val.transform;
			string[] array = path.Split(new char[1] { '/' });
			foreach (string text in array)
			{
				if (!string.IsNullOrEmpty(text))
				{
					Transform val3 = val2.Find(text);
					if ((Object)(object)val3 == (Object)null)
					{
						return null;
					}
					val2 = val3;
				}
			}
			return ((Component)val2).gameObject;
		}
	}
	public sealed class PerFrameCache<T>
	{
		private T _cachedValue;

		private int _cachedFrameCount;

		private readonly Func<T> _fetcher;

		private bool _hasValue;

		public T Value => Get();

		public bool HasValue => _hasValue;

		public PerFrameCache(Func<T> fetcher)
		{
			_fetcher = fetcher;
			_cachedFrameCount = -1;
		}

		public PerFrameCache()
		{
			_fetcher = null;
			_cachedFrameCount = -1;
		}

		public T Get()
		{
			int frameCount = Time.frameCount;
			if (_cachedFrameCount != frameCount)
			{
				_cachedValue = _fetcher();
				_cachedFrameCount = frameCount;
				_hasValue = true;
			}
			return _cachedValue;
		}

		public T Get(Func<T> fetcher)
		{
			int frameCount = Time.frameCount;
			if (_cachedFrameCount != frameCount)
			{
				_cachedValue = fetcher();
				_cachedFrameCount = frameCount;
				_hasValue = true;
			}
			return _cachedValue;
		}

		public void Invalidate()
		{
			_cachedFrameCount = -1;
			_hasValue = false;
		}

		public void Set(T value)
		{
			_cachedValue = value;
			_cachedFrameCount = Time.frameCount;
			_hasValue = true;
		}
	}
	public static class SingletonChecker
	{
		private const BindingFlags StaticFieldFlags = BindingFlags.Static | BindingFlags.Public;

		private const BindingFlags InstanceFieldFlags = BindingFlags.Instance | BindingFlags.Public;

		public static bool Exists(string typeName, string fieldName = "main", string assemblyName = "Assembly-CSharp")
		{
			if (string.IsNullOrEmpty(typeName))
			{
				throw new ArgumentException("Type name cannot be null or empty", "typeName");
			}
			Type type = ResolveType(typeName, assemblyName);
			if (type == null)
			{
				return false;
			}
			FieldInfo field = type.GetField(fieldName, BindingFlags.Static | BindingFlags.Public);
			if (field == null)
			{
				return false;
			}
			object value = field.GetValue(null);
			if (value == null)
			{
				return false;
			}
			Object val = (Object)((value is Object) ? value : null);
			if (val != null)
			{
				return val != (Object)null;
			}
			return true;
		}

		public static T GetValue<T>(string typeName, string fieldName = "main", string assemblyName = "Assembly-CSharp") where T : class
		{
			if (string.IsNullOrEmpty(typeName))
			{
				throw new ArgumentException("Type name cannot be null or empty", "typeName");
			}
			Type type = ResolveType(typeName, assemblyName);
			if (type == null)
			{
				throw new InvalidOperationException("Type '" + typeName + "' not found in assembly '" + assemblyName + "'");
			}
			FieldInfo field = type.GetField(fieldName, BindingFlags.Static | BindingFlags.Public);
			if (field == null)
			{
				throw new InvalidOperationException("Static field '" + fieldName + "' not found on type '" + typeName + "'");
			}
			return field.GetValue(null) as T;
		}

		public static bool TryGetValue<T>(string typeName, string fieldName, out T value, string assemblyName = "Assembly-CSharp") where T : class
		{
			value = null;
			if (string.IsNullOrEmpty(typeName))
			{
				return false;
			}
			Type type = ResolveType(typeName, assemblyName);
			if (type == null)
			{
				return false;
			}
			FieldInfo field = type.GetField(fieldName, BindingFlags.Static | BindingFlags.Public);
			if (field == null)
			{
				return false;
			}
			object value2 = field.GetValue(null);
			if (value2 == null)
			{
				return false;
			}
			Object val = (Object)((value2 is Object) ? value2 : null);
			if (val != null && val == (Object)null)
			{
				return false;
			}
			value = value2 as T;
			return value != null;
		}

		public static T GetInstanceField<T>(string singletonTypeName, string singletonFieldName, string instanceFieldName, string assemblyName = "Assembly-CSharp")
		{
			if (string.IsNullOrEmpty(singletonTypeName))
			{
				throw new ArgumentException("Singleton type name cannot be null or empty", "singletonTypeName");
			}
			if (string.IsNullOrEmpty(instanceFieldName))
			{
				throw new ArgumentException("Instance field name cannot be null or empty", "instanceFieldName");
			}
			Type type = ResolveType(singletonTypeName, assemblyName);
			if (type == null)
			{
				throw new InvalidOperationException("Type '" + singletonTypeName + "' not found");
			}
			FieldInfo field = type.GetField(singletonFieldName, BindingFlags.Static | BindingFlags.Public);
			if (field == null)
			{
				throw new InvalidOperationException("Static field '" + singletonFieldName + "' not found on type '" + singletonTypeName + "'");
			}
			object value = field.GetValue(null);
			if (value == null)
			{
				throw new InvalidOperationException("Singleton '" + singletonTypeName + "." + singletonFieldName + "' is null");
			}
			Object val = (Object)((value is Object) ? value : null);
			if (val != null && val == (Object)null)
			{
				throw new InvalidOperationException("Singleton '" + singletonTypeName + "." + singletonFieldName + "' is destroyed");
			}
			FieldInfo field2 = type.GetField(instanceFieldName, BindingFlags.Instance | BindingFlags.Public);
			if (field2 == null)
			{
				throw new InvalidOperationException("Instance field '" + instanceFieldName + "' not found on type '" + singletonTypeName + "'");
			}
			object value2 = field2.GetValue(value);
			if (value2 is T)
			{
				return (T)value2;
			}
			return default(T);
		}

		public static bool TryGetInstanceField<T>(string singletonTypeName, string singletonFieldName, string instanceFieldName, out T value, string assemblyName = "Assembly-CSharp")
		{
			value = default(T);
			if (string.IsNullOrEmpty(singletonTypeName) || string.IsNullOrEmpty(instanceFieldName))
			{
				return false;
			}
			Type type = ResolveType(singletonTypeName, assemblyName);
			if (type == null)
			{
				return false;
			}
			FieldInfo field = type.GetField(singletonFieldName, BindingFlags.Static | BindingFlags.Public);
			if (field == null)
			{
				return false;
			}
			object value2 = field.GetValue(null);
			if (value2 == null)
			{
				return false;
			}
			Object val = (Object)((value2 is Object) ? value2 : null);
			if (val != null && val == (Object)null)
			{
				return false;
			}
			FieldInfo field2 = type.GetField(instanceFieldName, BindingFlags.Instance | BindingFlags.Public);
			if (field2 == null)
			{
				return false;
			}
			if (field2.GetValue(value2) is T val2)
			{
				value = val2;
				return true;
			}
			return false;
		}

		public static bool IsActiveInHierarchy(string typeName, string fieldName = "main", string assemblyName = "Assembly-CSharp")
		{
			if (!TryGetValue<Component>(typeName, fieldName, out var value, assemblyName))
			{
				return false;
			}
			if ((Object)(object)value != (Object)null)
			{
				return value.gameObject.activeInHierarchy;
			}
			return false;
		}

		private static Type ResolveType(string typeName, string assemblyName)
		{
			Type type = Type.GetType(typeName + ", " + assemblyName);
			if (type != null)
			{
				return type;
			}
			type = Type.GetType(typeName);
			if (type != null)
			{
				return type;
			}
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			for (int i = 0; i < assemblies.Length; i++)
			{
				type = assemblies[i].GetType(typeName);
				if (type != null)
				{
					return type;
				}
			}
			return null;
		}
	}
}
namespace CameraUnlock.Core.Unity.UI
{
	public enum NotificationType
	{
		Info,
		Success,
		Warning,
		Error
	}
	public class NotificationUI
	{
		private const float DefaultDisplayDuration = 2f;

		private const float FadeDuration = 0.5f;

		private const int FontSize = 24;

		private const int ShadowOffset = 2;

		private const float VerticalPosition = 100f;

		private string _currentMessage;

		private float _displayTimer;

		private NotificationType _currentType;

		private GUIStyle _textStyle;

		private GUIStyle _shadowStyle;

		private bool _stylesInitialized;

		private static readonly Color InfoColor = Color.white;

		private static readonly Color SuccessColor = new Color(0.4f, 1f, 0.4f);

		private static readonly Color WarningColor = new Color(1f, 0.9f, 0.3f);

		private static readonly Color ErrorColor = new Color(1f, 0.4f, 0.4f);

		public bool IsDisplaying
		{
			get
			{
				if (_displayTimer > 0f)
				{
					return !string.IsNullOrEmpty(_currentMessage);
				}
				return false;
			}
		}

		public void ShowNotification(string message)
		{
			ShowNotification(message, NotificationType.Info, 2f);
		}

		public void ShowNotification(string message, float duration)
		{
			ShowNotification(message, NotificationType.Info, duration);
		}

		public void ShowNotification(string message, NotificationType type)
		{
			ShowNotification(message, type, 2f);
		}

		public void ShowNotification(string message, NotificationType type, float duration)
		{
			_currentMessage = message;
			_currentType = type;
			_displayTimer = duration + 0.5f;
		}

		public void ShowTrackingEnabled()
		{
			ShowNotification("Head Tracking: ON", NotificationType.Success);
		}

		public void ShowTrackingDisabled()
		{
			ShowNotification("Head Tracking: OFF", NotificationType.Warning);
		}

		public void ShowRecentered()
		{
			ShowNotification("Head Tracking: Recentered", NotificationType.Info);
		}

		public void ShowConnectionEstablished()
		{
			ShowNotification("OpenTrack: Connected", NotificationType.Success);
		}

		public void ShowConnectionLost()
		{
			ShowNotification("OpenTrack: No Signal", NotificationType.Warning);
		}

		public void Update()
		{
			if (_displayTimer > 0f)
			{
				_displayTimer -= Time.deltaTime;
			}
		}

		public void Draw()
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			if (!(_displayTimer <= 0f) && !string.IsNullOrEmpty(_currentMessage))
			{
				EnsureStyles();
				float num = 1f;
				if (_displayTimer < 0.5f)
				{
					num = _displayTimer / 0.5f;
				}
				Color colorForType = GetColorForType(_currentType);
				GUIContent val = new GUIContent(_currentMessage);
				Vector2 val2 = _textStyle.CalcSize(val);
				float num2 = ((float)Screen.width - val2.x) / 2f;
				float num3 = 100f;
				Rect val3 = new Rect(num2, num3, val2.x, val2.y);
				Rect val4 = new Rect(num2 + 2f, num3 + 2f, val2.x, val2.y);
				_shadowStyle.normal.textColor = new Color(0f, 0f, 0f, num * 0.8f);
				GUI.Label(val4, _currentMessage, _shadowStyle);
				_textStyle.normal.textColor = new Color(colorForType.r, colorForType.g, colorForType.b, num);
				GUI.Label(val3, _currentMessage, _textStyle);
			}
		}

		private static Color GetColorForType(NotificationType type)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			return (Color)(type switch
			{
				NotificationType.Success => SuccessColor, 
				NotificationType.Warning => WarningColor, 
				NotificationType.Error => ErrorColor, 
				_ => InfoColor, 
			});
		}

		private void EnsureStyles()
		{
			//IL_0014: 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)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			if (!_stylesInitialized)
			{
				_textStyle = new GUIStyle(GUI.skin.label)
				{
					fontSize = 24,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)4
				};
				_textStyle.normal.textColor = Color.white;
				_shadowStyle = new GUIStyle(_textStyle);
				_shadowStyle.normal.textColor = Color.black;
				_stylesInitialized = true;
			}
		}
	}
	public class StatusIndicatorUI
	{
		private const int FontSize = 14;

		private const int Padding = 10;

		private const int ShadowOffset = 1;

		private const float BackgroundAlpha = 0.4f;

		private GUIStyle _textStyle;

		private GUIStyle _shadowStyle;

		private GUIStyle _backgroundStyle;

		private Texture2D _backgroundTexture;

		private bool _stylesInitialized;

		private bool _enabled = true;

		private StatusPosition _position = StatusPosition.BottomRight;

		private bool _trackingEnabled;

		private bool _isReceiving;

		private bool _cachedTrackingEnabled;

		private bool _cachedIsReceiving;

		private string _statusText;

		private string _trackingStatus;

		private string _connectionStatus;

		private float _width;

		private float _height;

		private float _textWidth;

		private float _textHeight;

		private float _offset1;

		private float _offset2;

		private float _offset3;

		private float _offset4;

		private bool _layoutDirty = true;

		private const string PrefixHT = "[HT:";

		private const string PrefixOT = "] [OT:";

		private const string Suffix = "]";

		private const string StatusOn = "ON";

		private const string StatusOff = "OFF";

		private const string ConnOk = "OK";

		private const string ConnNone = "--";

		private static readonly Color EnabledColor = new Color(0.4f, 1f, 0.4f);

		private static readonly Color DisabledColor = new Color(0.6f, 0.6f, 0.6f);

		private static readonly Color ConnectedColor = new Color(0.4f, 1f, 0.4f);

		private static readonly Color DisconnectedColor = new Color(1f, 0.5f, 0.3f);

		public bool Enabled
		{
			get
			{
				return _enabled;
			}
			set
			{
				_enabled = value;
			}
		}

		public StatusPosition Position
		{
			get
			{
				return _position;
			}
			set
			{
				if (_position != value)
				{
					_position = value;
					_layoutDirty = true;
				}
			}
		}

		public void UpdateState(bool trackingEnabled, bool isReceiving)
		{
			_trackingEnabled = trackingEnabled;
			_isReceiving = isReceiving;
			if (_trackingEnabled != _cachedTrackingEnabled || _isReceiving != _cachedIsReceiving)
			{
				_layoutDirty = true;
			}
		}

		public void Draw()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			if (_enabled)
			{
				EnsureStyles();
				if (_layoutDirty)
				{
					RecalculateLayout();
				}
				Rect val = CalculatePosition(_width, _height);
				Rect rect = default(Rect);
				((Rect)(ref rect))..ctor(((Rect)(ref val)).x + 10f, ((Rect)(ref val)).y + 5f, _textWidth, _textHeight);
				Rect val2 = new Rect(((Rect)(ref rect)).x + 1f, ((Rect)(ref rect)).y + 1f, _textWidth, _textHeight);
				GUI.Box(val, GUIContent.none, _backgroundStyle);
				_shadowStyle.normal.textColor = new Color(0f, 0f, 0f, 0.6f);
				GUI.Label(val2, _statusText, _shadowStyle);
				DrawColoredStatus(rect);
			}
		}

		public void Dispose()
		{
			if ((Object)(object)_backgroundTexture != (Object)null)
			{
				Object.Destroy((Object)(object)_backgroundTexture);
				_backgroundTexture = null;
			}
		}

		private void RecalculateLayout()
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Expected O, but got Unknown
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Expected O, but got Unknown
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Expected O, but got Unknown
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Expected O, but got Unknown
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			_trackingStatus = (_trackingEnabled ? "ON" : "OFF");
			_connectionStatus = (_isReceiving ? "OK" : "--");
			_statusText = string.Format("{0}{1}{2}{3}{4}", "[HT:", _trackingStatus, "] [OT:", _connectionStatus, "]");
			GUIContent val = new GUIContent(_statusText);
			Vector2 val2 = _textStyle.CalcSize(val);
			_textWidth = val2.x;
			_textHeight = val2.y;
			_width = _textWidth + 20f;
			_height = _textHeight + 10f;
			_offset1 = _textStyle.CalcSize(new GUIContent("[HT:")).x;
			_offset2 = _offset1 + _textStyle.CalcSize(new GUIContent(_trackingStatus)).x;
			_offset3 = _offset2 + _textStyle.CalcSize(new GUIContent("] [OT:")).x;
			_offset4 = _offset3 + _textStyle.CalcSize(new GUIContent(_connectionStatus)).x;
			_cachedTrackingEnabled = _trackingEnabled;
			_cachedIsReceiving = _isReceiving;
			_layoutDirty = false;
		}

		private void DrawColoredStatus(Rect rect)
		{
			//IL_000f: 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_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			Color textColor = (_trackingEnabled ? EnabledColor : DisabledColor);
			Color textColor2 = (_isReceiving ? ConnectedColor : DisconnectedColor);
			_textStyle.normal.textColor = Color.white;
			GUI.Label(rect, "[HT:", _textStyle);
			Rect val = new Rect(((Rect)(ref rect)).x + _offset1, ((Rect)(ref rect)).y, ((Rect)(ref rect)).width - _offset1, ((Rect)(ref rect)).height);
			_textStyle.normal.textColor = textColor;
			GUI.Label(val, _trackingStatus, _textStyle);
			Rect val2 = new Rect(((Rect)(ref rect)).x + _offset2, ((Rect)(ref rect)).y, ((Rect)(ref rect)).width - _offset2, ((Rect)(ref rect)).height);
			_textStyle.normal.textColor = Color.white;
			GUI.Label(val2, "] [OT:", _textStyle);
			Rect val3 = new Rect(((Rect)(ref rect)).x + _offset3, ((Rect)(ref rect)).y, ((Rect)(ref rect)).width - _offset3, ((Rect)(ref rect)).height);
			_textStyle.normal.textColor = textColor2;
			GUI.Label(val3, _connectionStatus, _textStyle);
			Rect val4 = new Rect(((Rect)(ref rect)).x + _offset4, ((Rect)(ref rect)).y, ((Rect)(ref rect)).width - _offset4, ((Rect)(ref rect)).height);
			_textStyle.normal.textColor = Color.white;
			GUI.Label(val4, "]", _textStyle);
		}

		private Rect CalculatePosition(float width, float height)
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			float num;
			float num2;
			switch (_position)
			{
			case StatusPosition.TopLeft:
				num = 10f;
				num2 = 10f;
				break;
			case StatusPosition.TopRight:
				num = (float)Screen.width - width - 10f;
				num2 = 10f;
				break;
			case StatusPosition.BottomLeft:
				num = 10f;
				num2 = (float)Screen.height - height - 10f;
				break;
			default:
				num = (float)Screen.width - width - 10f;
				num2 = (float)Screen.height - height - 10f;
				break;
			}
			return new Rect(num, num2, width, height);
		}

		private void EnsureStyles()
		{
			//IL_0014: 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)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Expected O, but got Unknown
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Expected O, but got Unknown
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			if (!_stylesInitialized)
			{
				_textStyle = new GUIStyle(GUI.skin.label)
				{
					fontSize = 14,
					fontStyle = (FontStyle)1,
					alignment = (TextAnchor)3
				};
				_textStyle.normal.textColor = Color.white;
				_shadowStyle = new GUIStyle(_textStyle);
				_shadowStyle.normal.textColor = Color.black;
				_backgroundStyle = new GUIStyle(GUI.skin.box);
				_backgroundTexture = new Texture2D(1, 1);
				_backgroundTexture.SetPixel(0, 0, new Color(0f, 0f, 0f, 0.4f));
				_backgroundTexture.Apply();
				_backgroundStyle.normal.background = _backgroundTexture;
				_stylesInitialized = true;
				_layoutDirty = true;
			}
		}
	}
	public enum StatusPosition
	{
		TopLeft,
		TopRight,
		BottomLeft,
		BottomRight
	}
	public abstract class UIElementOffsetController : MonoBehaviour
	{
		private bool _targetAcquired;

		private bool _originalStateCaptured;

		private bool _wasDecoupled;

		public bool EnableLogging { get; set; }

		public Action<string> Log { get; set; }

		public Func<bool> IsDecouplingActive { get; set; }

		public Func<Vector2> GetScreenOffset { get; set; }

		public Func<float> GetCanvasScaleFactor { get; set; }

		protected virtual void Start()
		{
			_targetAcquired = false;
			_originalStateCaptured = false;
			_wasDecoupled = false;
			LogMessage(((object)this).GetType().Name + " initialized");
		}

		protected virtual void LateUpdate()
		{
			if (EnsureTarget())
			{
				bool flag = IsDecouplingActive != null && IsDecouplingActive();
				if (flag)
				{
					ApplyCurrentOffset();
				}
				else if (_wasDecoupled)
				{
					RestoreOriginalState();
				}
				_wasDecoupled = flag;
			}
		}

		protected virtual void OnDestroy()
		{
			if (_originalStateCaptured)
			{
				RestoreOriginalState();
			}
		}

		private bool EnsureTarget()
		{
			if (!_targetAcquired)
			{
				if (!TryAcquireTarget())
				{
					return false;
				}
				_targetAcquired = true;
				LogMessage("Target acquired");
			}
			if (!_originalStateCaptured)
			{
				CaptureOriginalState();
				_originalStateCaptured = true;
				LogMessage("Original state captured");
			}
			return true;
		}

		private void ApplyCurrentOffset()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			if (GetScreenOffset == null)
			{
				return;
			}
			Vector2 val = GetScreenOffset();
			if (GetCanvasScaleFactor != null)
			{
				float num = GetCanvasScaleFactor();
				if (num > 0f)
				{
					val /= num;
				}
			}
			ApplyOffset(val);
		}

		public void ResetReferences()
		{
			if (_originalStateCaptured)
			{
				RestoreOriginalState();
			}
			ClearReferences();
			_targetAcquired = false;
			_originalStateCaptured = false;
			_wasDecoupled = false;
			LogMessage("References reset");
		}

		protected void LogMessage(string message)
		{
			if (EnableLogging && Log != null)
			{
				Log("[" + ((object)this).GetType().Name + "] " + message);
			}
		}

		protected abstract bool TryAcquireTarget();

		protected abstract void CaptureOriginalState();

		protected abstract void ApplyOffset(Vector2 offset);

		protected abstract void RestoreOriginalState();

		protected abstract void ClearReferences();
	}
}
namespace CameraUnlock.Core.Unity.Tracking
{
	public class BaseRotationTracker
	{
		private Quaternion _baseRotation = Quaternion.identity;

		private Quaternion _headTrackingRotation = Quaternion.identity;

		private Transform _trackedTransform;

		private bool _hasValidData;

		public Quaternion BaseRotation => _baseRotation;

		public Quaternion HeadTrackingRotation => _headTrackingRotation;

		public Quaternion CombinedRotation => _baseRotation * _headTrackingRotation;

		public Vector3 BaseForward => _baseRotation * Vector3.forward;

		public Vector3 CombinedForward => CombinedRotation * Vector3.forward;

		public bool HasValidData => _hasValidData;

		public Transform TrackedTransform => _trackedTransform;

		public void Update(Transform cameraTransform, Quaternion gameWantedRotation, Quaternion headTrackingRotation)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			_trackedTransform = cameraTransform;
			_headTrackingRotation = headTrackingRotation;
			if ((Object)(object)cameraTransform != (Object)null && (Object)(object)cameraTransform.parent != (Object)null)
			{
				_baseRotation = cameraTransform.parent.rotation * gameWantedRotation;
			}
			else
			{
				_baseRotation = gameWantedRotation;
			}
			_hasValidData = true;
		}

		public void UpdateBaseOnly(Transform cameraTransform, Quaternion gameWantedRotation)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			Update(cameraTransform, gameWantedRotation, Quaternion.identity);
		}

		public Quaternion GetBaseLocalRotation()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_trackedTransform == (Object)null)
			{
				return _baseRotation;
			}
			if ((Object)(object)_trackedTransform.parent != (Object)null)
			{
				return Quaternion.Inverse(_trackedTransform.parent.rotation) * _baseRotation;
			}
			return _baseRotation;
		}

		public Quaternion GetCombinedLocalRotation()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			Quaternion combinedRotation = CombinedRotation;
			if ((Object)(object)_trackedTransform == (Object)null)
			{
				return combinedRotation;
			}
			if ((Object)(object)_trackedTransform.parent != (Object)null)
			{
				return Quaternion.Inverse(_trackedTransform.parent.rotation) * combinedRotation;
			}
			return combinedRotation;
		}

		public Vector3 ProjectBaseForwardToScreen(Camera camera, float distance = 100f)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)camera == (Object)null || !_hasValidData)
			{
				return new Vector3((float)Screen.width * 0.5f, (float)Screen.height * 0.5f, 0f);
			}
			Vector3 val = ((Component)camera).transform.position + BaseForward * distance;
			return camera.WorldToScreenPoint(val);
		}

		public float GetAimViewAngle()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (!_hasValidData)
			{
				return 0f;
			}
			return Vector3.Angle(BaseForward, CombinedForward);
		}

		public void Reset()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			_baseRotation = Quaternion.identity;
			_headTrackingRotation = Quaternion.identity;
			_trackedTransform = null;
			_hasValidData = false;
		}
	}
	public sealed class CameraCallbackLifecycle : IDisposable
	{
		private static CameraCallback _staticPreCullCallback;

		private static CameraCallback _staticPreRenderCallback;

		private static Action _staticWillRenderCanvasesCallback;

		private bool _ownsPreCull;

		private bool _ownsPreRender;

		private bool _ownsWillRenderCanvases;

		private bool _disposed;

		public bool HasPreCull
		{
			get
			{
				if (_ownsPreCull)
				{
					return !_disposed;
				}
				return false;
			}
		}

		public bool HasPreRender
		{
			get
			{
				if (_ownsPreRender)
				{
					return !_disposed;
				}
				return false;
			}
		}

		public bool HasWillRenderCanvases
		{
			get
			{
				if (_ownsWillRenderCanvases)
				{
					return !_disposed;
				}
				return false;
			}
		}

		public bool IsDisposed => _disposed;

		public void RegisterPreCull(CameraCallback callback)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			if (_disposed)
			{
				throw new ObjectDisposedException("CameraCallbackLifecycle");
			}
			if (callback == null)
			{
				throw new ArgumentNullException("callback");
			}
			if (_staticPreCullCallback != null)
			{
				throw new InvalidOperationException("A preCull callback is already registered. Call UnregisterPreCull first or Dispose the previous lifecycle.");
			}
			_staticPreCullCallback = callback;
			Camera.onPreCull = (CameraCallback)Delegate.Combine((Delegate?)(object)Camera.onPreCull, (Delegate?)(object)_staticPreCullCallback);
			_ownsPreCull = true;
		}

		public void UnregisterPreCull()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			if (_ownsPreCull && _staticPreCullCallback != null)
			{
				Camera.onPreCull = (CameraCallback)Delegate.Remove((Delegate?)(object)Camera.onPreCull, (Delegate?)(object)_staticPreCullCallback);
				_staticPreCullCallback = null;
				_ownsPreCull = false;
			}
		}

		public void RegisterPreRender(CameraCallback callback)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			if (_disposed)
			{
				throw new ObjectDisposedException("CameraCallbackLifecycle");
			}
			if (callback == null)
			{
				throw new ArgumentNullException("callback");
			}
			if (_staticPreRenderCallback != null)
			{
				throw new InvalidOperationException("A preRender callback is already registered. Call UnregisterPreRender first or Dispose the previous lifecycle.");
			}
			_staticPreRenderCallback = callback;
			Camera.onPreRender = (CameraCallback)Delegate.Combine((Delegate?)(object)Camera.onPreRender, (Delegate?)(object)_staticPreRenderCallback);
			_ownsPreRender = true;
		}

		public void UnregisterPreRender()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			if (_ownsPreRender && _staticPreRenderCallback != null)
			{
				Camera.onPreRender = (CameraCallback)Delegate.Remove((Delegate?)(object)Camera.onPreRender, (Delegate?)(object)_staticPreRenderCallback);
				_staticPreRenderCallback = null;
				_ownsPreRender = false;
			}
		}

		public void RegisterWillRenderCanvases(Action callback)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			if (_disposed)
			{
				throw new ObjectDisposedException("CameraCallbackLifecycle");
			}
			if (callback == null)
			{
				throw new ArgumentNullException("callback");
			}
			if (_staticWillRenderCanvasesCallback != null)
			{
				throw new InvalidOperationException("A willRenderCanvases callback is already registered. Call UnregisterWillRenderCanvases first or Dispose the previous lifecycle.");
			}
			_staticWillRenderCanvasesCallback = callback;
			Canvas.willRenderCanvases += new WillRenderCanvases(OnWillRenderCanvasesWrapper);
			_ownsWillRenderCanvases = true;
		}

		public void UnregisterWillRenderCanvases()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			if (_ownsWillRenderCanvases && _staticWillRenderCanvasesCallback != null)
			{
				Canvas.willRenderCanvases -= new WillRenderCanvases(OnWillRenderCanvasesWrapper);
				_staticWillRenderCanvasesCallback = null;
				_ownsWillRenderCanvases = false;
			}
		}

		private static void OnWillRenderCanvasesWrapper()
		{
			_staticWillRenderCanvasesCallback?.Invoke();
		}

		public void Dispose()
		{
			if (!_disposed)
			{
				UnregisterPreCull();
				UnregisterPreRender();
				UnregisterWillRenderCanvases();
				_disposed = true;
			}
		}

		public static void ForceCleanupAll()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			if (_staticPreCullCallback != null)
			{
				Camera.onPreCull = (CameraCallback)Delegate.Remove((Delegate?)(object)Camera.onPreCull, (Delegate?)(object)_staticPreCullCallback);
				_staticPreCullCallback = null;
			}
			if (_staticPreRenderCallback != null)
			{
				Camera.onPreRender = (CameraCallback)Delegate.Remove((Delegate?)(object)Camera.onPreRender, (Delegate?)(object)_staticPreRenderCallback);
				_staticPreRenderCallback = null;
			}
			if (_staticWillRenderCanvasesCallback != null)
			{
				Canvas.willRenderCanvases -= new WillRenderCanvases(OnWillRenderCanvasesWrapper);
				_staticWillRenderCanvasesCallback = null;
			}
		}
	}
	public abstract class CameraLifecycleManager : MonoBehaviour
	{
		private Camera _trackedCamera;

		private Component _trackingHook;

		private float _lastLogTime;

		private float _logInterval = 5f;

		public Camera TrackedCamera => _trackedCamera;

		public Component TrackingHook => _trackingHook;

		public bool IsTracking => (Object)(object)_trackedCamera != (Object)null;

		public bool IsHookAttached
		{
			get
			{
				if ((Object)(object)_trackingHook != (Object)null)
				{
					return (Object)(object)_trackingHook.gameObject != (Object)null;
				}
				return false;
			}
		}

		public float LogInterval
		{
			get
			{
				return _logInterval;
			}
			set
			{
				_logInterval = value;
			}
		}

		protected virtual void LateUpdate()
		{
			Camera val = FindCamera();
			if ((Object)(object)val == (Object)null)
			{
				HandleCameraLost();
			}
			else if (NeedsHookAttachment(val))
			{
				AttachHook(val);
			}
		}

		protected virtual bool NeedsHookAttachment(Camera camera)
		{
			if ((Object)(object)_trackingHook == (Object)null)
			{
				return true;
			}
			if ((Object)(object)_trackingHook.gameObject == (Object)null)
			{
				return true;
			}
			if ((Object)(object)_trackedCamera != (Object)(object)camera)
			{
				return true;
			}
			if ((Object)(object)_trackingHook.gameObject != (Object)(object)((Component)camera).gameObject)
			{
				return true;
			}
			return false;
		}

		private void AttachHook(Camera camera)
		{
			if ((Object)(object)_trackingHook != (Object)null && (Object)(object)_trackingHook.gameObject != (Object)null)
			{
				Object.Destroy((Object)(object)_trackingHook);
				_trackingHook = null;
			}
			Component val = FindExistingHook(camera);
			if ((Object)(object)val != (Object)null)
			{
				_trackingHook = val;
				_trackedCamera = camera;
				OnCameraFound(camera, val, isReused: true);
				return;
			}
			_trackingHook = CreateTrackingHook(camera);
			if ((Object)(object)_trackingHook != (Object)null)
			{
				_trackedCamera = camera;
				OnCameraFound(camera, _trackingHook, isReused: false);
			}
		}

		private void HandleCameraLost()
		{
			if ((Object)(object)_trackedCamera != (Object)null)
			{
				float unscaledTime = Time.unscaledTime;
				if (_logInterval <= 0f || unscaledTime - _lastLogTime > _logInterval)
				{
					OnCameraLost();
					_lastLogTime = unscaledTime;
				}
				_trackedCamera = null;
				_trackingHook = null;
			}
		}

		public void ForceRefresh()
		{
			_trackedCamera = null;
			_trackingHook = null;
		}

		protected abstract Camera FindCamera();

		protected abstract Component CreateTrackingHook(Camera camera);

		protected virtual void OnCameraFound(Camera camera, Component hook, bool isReused)
		{
		}

		protected virtual void OnCameraLost()
		{
		}

		protected virtual Component FindExistingHook(Camera camera)
		{
			return null;
		}

		protected virtual void OnDestroy()
		{
			if ((Object)(object)_trackingHook != (Object)null && (Object)(object)_trackingHook.gameObject != (Object)null)
			{
				Object.Destroy((Object)(object)_trackingHook);
			}
		}
	}
	public static class CameraRotationComposer
	{
		public static Quaternion ComposeAdditive(Quaternion gameRotation, float headYaw, float headPitch, float headRoll)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: 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)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			Quaternion val = Quaternion.AngleAxis(headYaw, Vector3.up);
			Quaternion val2 = Quaternion.Euler(0f - headPitch, 0f, headRoll);
			return val * gameRotation * val2;
		}

		public static Quaternion ComposeYXZ(Quaternion gameYaw, float gamePitch, float trackYaw, float trackPitch, float trackRoll)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			float num = gamePitch + trackPitch;
			Quaternion val = gameYaw * Quaternion.AngleAxis(trackYaw, Vector3.up);
			Quaternion val2 = Quaternion.AngleAxis(num, Vector3.right);
			Quaternion val3 = Quaternion.AngleAxis(trackRoll, Vector3.forward);
			return val * val2 * val3;
		}

		public static Quaternion ComposeYXZClamped(Quaternion gameYaw, float gamePitch, float trackYaw, float trackPitch, float trackRoll, float minPitch, float maxPitch)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Clamp(gamePitch + trackPitch, minPitch, maxPitch);
			Quaternion val = gameYaw * Quaternion.AngleAxis(trackYaw, Vector3.up);
			Quaternion val2 = Quaternion.AngleAxis(num, Vector3.right);
			Quaternion val3 = Quaternion.AngleAxis(trackRoll, Vector3.forward);
			return val * val2 * val3;
		}

		public static Quaternion GetTrackingOnlyRotation(float trackYaw, float trackPitch, float trackRoll)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			Quaternion val = Quaternion.AngleAxis(trackYaw, Vector3.up);
			Quaternion val2 = Quaternion.AngleAxis(trackPitch, Vector3.right);
			Quaternion val3 = Quaternion.AngleAxis(trackRoll, Vector3.forward);
			return val * val2 * val3;
		}

		public static Quaternion ComposeFirstPerson(Quaternion baseLookRotation, float headYaw, float headPitch, float headRoll)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			return ComposeAdditive(baseLookRotation, headYaw, headPitch, headRoll);
		}
	}
	public class CameraSpeedInfluenceModifier : IInfluenceModifier
	{
		private float _currentSpeed;

		private float _lastDegreesX;

		private float _lastDegreesY;

		private bool _initialized;

		public float SpeedThreshold { get; set; } = 2f;


		public float SpeedRange { get; set; } = 8f;


		public float MinInfluence { get; set; } = 0.15f;


		public float CurrentSpeed => _currentSpeed;

		public CameraSpeedInfluenceModifier()
		{
		}

		public CameraSpeedInfluenceModifier(float speedThreshold, float speedRange, float minInfluence)
		{
			SpeedThreshold = speedThreshold;
			SpeedRange = speedRange;
			MinInfluence = minInfluence;
		}

		public void UpdateFromDegrees(float degreesX, float degreesY)
		{
			if (!_initialized)
			{
				_lastDegreesX = degreesX;
				_lastDegreesY = degreesY;
				_initialized = true;
				_currentSpeed = 0f;
			}
			else
			{
				float num = degreesX - _lastDegreesX;
				float num2 = degreesY - _lastDegreesY;
				_currentSpeed = Mathf.Sqrt(num * num + num2 * num2);
				_lastDegreesX = degreesX;
				_lastDegreesY = degreesY;
			}
		}

		public void UpdateFromRotation(Quaternion previousRotation, Quaternion currentRotation)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			float currentSpeed = Quaternion.Angle(previousRotation, currentRotation);
			_currentSpeed = currentSpeed;
		}

		public void SetSpeed(float speed)
		{
			_currentSpeed = speed;
		}

		public float GetInfluence()
		{
			if (_currentSpeed <= SpeedThreshold)
			{
				return 1f;
			}
			if (SpeedRange <= 0f)
			{
				return MinInfluence;
			}
			float num = Mathf.Clamp01((_currentSpeed - SpeedThreshold) / SpeedRange);
			return Mathf.Lerp(1f, MinInfluence, num);
		}

		public void Reset()
		{
			_currentSpeed = 0f;
			_lastDegreesX = 0f;
			_lastDegreesY = 0f;
			_initialized = false;
		}
	}
	public static class DecoupledMovementHelper
	{
		public static void ApplyDecoupled(Transform playerBodyTransform, Transform cameraTransform, float pureAimYaw, float trackingYaw, float trackingPitch, float trackingRoll, bool invertPitch = true)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)playerBodyTransform == (Object)null))
			{
				float num = NormalizeAngle(pureAimYaw);
				float num2 = (invertPitch ? (0f - trackingPitch) : trackingPitch);
				playerBodyTransform.localEulerAngles = new Vector3(num2, num, trackingRoll);
				if ((Object)(object)cameraTransform != (Object)null && (Object)(object)cameraTransform != (Object)(object)playerBodyTransform)
				{
					Vector3 localEulerAngles = cameraTransform.localEulerAngles;
					cameraTransform.localEulerAngles = new Vector3(localEulerAngles.x, trackingYaw, localEulerAngles.z);
				}
			}
		}

		public static void ApplyDecoupledFadeOut(Transform playerBodyTransform, Transform cameraTransform, float pureAimYaw, float lastTrackingYaw, float lastTrackingPitch, float lastTrackingRoll, float fadeProgress, bool invertPitch = true)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: 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_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)playerBodyTransform == (Object)null))
			{
				float num = Mathf.Lerp(lastTrackingYaw, 0f, fadeProgress);
				float num2 = Mathf.Lerp(lastTrackingPitch, 0f, fadeProgress);
				float num3 = Mathf.Lerp(lastTrackingRoll, 0f, fadeProgress);
				float num4 = NormalizeAngle(pureAimYaw);
				float num5 = (invertPitch ? (0f - num2) : num2);
				playerBodyTransform.localEulerAngles = new Vector3(num5, num4, num3);
				if ((Object)(object)cameraTransform != (Object)null && (Object)(object)cameraTransform != (Object)(object)playerBodyTransform)
				{
					Vector3 localEulerAngles = cameraTransform.localEulerAngles;
					cameraTransform.localEulerAngles = new Vector3(localEulerAngles.x, num, localEulerAngles.z);
				}
			}
		}

		public static void ResetCameraYawOffset(Transform cameraTransform, Transform playerBodyTransform)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)cameraTransform != (Object)null && (Object)(object)cameraTransform != (Object)(object)playerBodyTransform)
			{
				Vector3 localEulerAngles = cameraTransform.localEulerAngles;
				cameraTransform.localEulerAngles = new Vector3(localEulerAngles.x, 0f, localEulerAngles.z);
			}
		}

		private static float NormalizeAngle(float angle)
		{
			while (angle < 0f)
			{
				angle += 360f;
			}
			while (angle >= 360f)
			{
				angle -= 360f;
			}
			return angle;
		}

		public static float ToSignedAngle(float angle)
		{
			if (angle > 180f)
			{
				return angle - 360f;
			}
			return angle;
		}
	}
	public abstract class LookAimDecoupledHook : MonoBehaviour
	{
		private Camera _camera;

		private Quaternion _preTrackingRotation;

		private bool _trackingAppliedThisFrame;

		private bool _isEnabled = true;

		public bool IsEnabled
		{
			get
			{
				return _isEnabled;
			}
			set
			{
				_isEnabled = value;
			}
		}

		protected Camera Camera => _camera;

		protected bool TrackingAppliedThisFrame => _trackingAppliedThisFrame;

		protected Quaternion PreTrackingRotation => _preTrackingRotation;

		protected virtual void Awake()
		{
			_camera = ((Component)this).GetComponent<Camera>();
		}

		protected abstract Quaternion ComputeTrackedRotation(Quaternion gameRotation);

		protected abstract bool ShouldApplyTracking();

		protected virtual void OnPreCullComplete(Quaternion gameRotation, Quaternion trackedRotation)
		{
		}

		protected virtual void OnPostRenderComplete()
		{
		}

		private void OnPreCull()
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			_trackingAppliedThisFrame = false;
			try
			{
				if (_isEnabled && !((Object)(object)_camera == (Object)null) && ShouldApplyTracking())
				{
					_preTrackingRotation = ((Component)_camera).transform.rotation;
					_trackingAppliedThisFrame = true;
					Quaternion val = ComputeTrackedRotation(_preTrackingRotation);
					((Component)_camera).transform.rotation = val;
					OnPreCullComplete(_preTrackingRotation, val);
				}
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[LookAimDecoupledHook] OnPreCull error: " + ex.Message));
			}
		}

		private void OnPostRender()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if (!_trackingAppliedThisFrame)
			{
				return;
			}
			try
			{
				if ((Object)(object)_camera != (Object)null)
				{
					((Component)_camera).transform.rotation = _preTrackingRotation;
				}
				OnPostRenderComplete();
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("[LookAimDecoupledHook] OnPostRender error: " + ex.Message));
			}
		}
	}
	public static class PositionApplicator
	{
		public static Vector3 ToHorizonLockedWorld(Vec3 offset, Quaternion gameRotation)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = gameRotation * Vector3.forward;
			val.y = 0f;
			float magnitude = ((Vector3)(ref val)).magnitude;
			val = ((!(magnitude > 0.001f)) ? Vector3.forward : (val / magnitude));
			return new Vector3(val.z, 0f, 0f - val.x) * offset.X + Vector3.up * offset.Y + val * offset.Z;
		}

		public static Vector3 ToCameraLocalWorld(Vec3 offset, Quaternion gameRotation)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: 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_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			return gameRotation * new Vector3(offset.X, offset.Y, offset.Z);
		}
	}
	public class SmoothedRotationState
	{
		private Quaternion _smoothedRotation = Quaternion.identity;

		private bool _initialized;

		public Quaternion Current => _smoothedRotation;

		public bool IsInitialized => _initialized;

		public Quaternion Update(Quaternion target, float smoothing)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			float effectiveSmoothing = SmoothingUtils.GetEffectiveSmoothing(smoothing);
			if (!_initialized)
			{
				_smoothedRotation = target;
				_initialized = true;
				return _smoothedRotation;
			}
			if (effectiveSmoothing < 0.001f)
			{
				_smoothedRotation = target;
				return _smoothedRotation;
			}
			_smoothedRotation = UnitySmoothingHelper.SmoothRotation(_smoothedRotation, target, effectiveSmoothing);
			return _smoothedRotation;
		}

		public void Reset()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			_smoothedRotation = Quaternion.identity;
			_initialized = false;
		}

		public void Reset(Quaternion rotation)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			_smoothedRotation = rotation;
			_initialized = true;
		}
	}
	public sealed class TemporaryRotationScope : IDisposable
	{
		private Quaternion _savedRotation;

		private Transform _transform;

		private bool _isActive;

		private TemporaryRotationScope()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			_savedRotation = Quaternion.identity;
			_transform = null;
			_isActive = false;
		}

		public static TemporaryRotationScope Apply(Transform transform, Quaternion newRotation)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)transform == (Object)null)
			{
				return null;
			}
			TemporaryRotationScope result = new TemporaryRotationScope
			{
				_savedRotation = transform.localRotation,
				_transform = transform,
				_isActive = true
			};
			transform.localRotation = newRotation;
			return result;
		}

		public static TemporaryRotationScope ApplyBaseRotation(Transform cameraTransform, Quaternion baseRotation, Quaternion headTrackingRotation)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)cameraTransform == (Object)null)
			{
				return null;
			}
			if (baseRotation == default(Quaternion) || headTrackingRotation == Quaternion.identity)
			{
				return null;
			}
			Quaternion val = baseRotation * headTrackingRotation;
			Quaternion newRotation = (((Object)(object)cameraTransform.parent != (Object)null) ? (Quaternion.Inverse(cameraTransform.parent.rotation) * val) : val);
			return Apply(cameraTransform, newRotation);
		}

		public static TemporaryRotationScope RemoveHeadTracking(Transform cameraTransform, Quaternion baseRotation)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)cameraTransform == (Object)null || baseRotation == default(Quaternion))
			{
				return null;
			}
			Quaternion newRotation = (((Object)(object)cameraTransform.parent != (Object)null) ? (Quaternion.Inverse(cameraTransform.parent.rotation) * baseRotation) : baseRotation);
			return Apply(cameraTransform, newRotation);
		}

		public void Dispose()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			if (_isActive && !((Object)(object)_transform == (Object)null))
			{
				_transform.localRotation = _savedRotation;
				_isActive = false;
				_transform = null;
				_savedRotation = Quaternion.identity;
			}
		}
	}
	public sealed class TemporaryWorldRotationScope : IDisposable
	{
		private Quaternion _savedRotation;

		private Transform _transform;

		private bool _isActive;

		private TemporaryWorldRotationScope()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			_savedRotation = Quaternion.identity;
			_transform = null;
			_isActive = false;
		}

		public static TemporaryWorldRotationScope Apply(Transform transform, Quaternion newWorldRotation)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)transform == (Object)null)
			{
				return null;
			}
			TemporaryWorldRotationScope result = new TemporaryWorldRotationScope
			{
				_savedRotation = transform.rotation,
				_transform = transform,
				_isActive = true
			};
			transform.rotation = newWorldRotation;
			return result;
		}

		public static TemporaryWorldRotationScope ApplyHeadTracking(Transform transform, Quaternion baseRotation, Quaternion headTrackingRotation)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)transform == (Object)null)
			{
				return null;
			}
			if (baseRotation == default(Quaternion) || headTrackingRotation == Quaternion.identity)
			{
				return null;
			}
			return Apply(transform, baseRotation * headTrackingRotation);
		}

		public void Dispose()
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			if (_isActive && !((Object)(object)_transform == (Object)null))
			{
				_transform.rotation = _savedRotation;
				_isActive = false;
				_transform = null;
				_savedRotation = Quaternion.identity;
			}
		}
	}
	public class TrackingLossHandler
	{
		private int _framesWithoutData;

		private float _secondsWithoutData;

		private int _stabilizationFramesRemaining;

		private bool _needsRecenter;

		private TrackingLossState _currentState;

		public float FadeDelaySeconds { get; set; } = 0.5f;


		public float FadeSpeed { get; set; } = 2f;


		public int StabilizationFrames { get; set; } = 10;


		public int RecenterThresholdFrames { get; set; } = 60;


		public TrackingLossState CurrentState => _currentState;

		public bool NeedsRecenter => _needsRecenter;

		public int StabilizationFramesRemaining => _stabilizationFramesRemaining;

		public TrackingLossHandler()
		{
			Reset();
		}

		public TrackingLossState Update(bool hasValidData, float deltaTime)
		{
			if (!hasValidData)
			{
				_framesWithoutData++;
				_secondsWithoutData += deltaTime;
				_stabilizationFramesRemaining = StabilizationFrames;
				if (RecenterThresholdFrames > 0 && _framesWithoutData > RecenterThresholdFrames)
				{
					_needsRecenter = true;
				}
				if (_secondsWithoutData <= FadeDelaySeconds)
				{
					_currentState = TrackingLossState.Holding;
				}
				else
				{
					_currentState = TrackingLossState.Fading;
				}
			}
			else
			{
				_framesWithoutData = 0;
				_secondsWithoutData = 0f;
				if (_stabilizationFramesRemaining > 0)
				{
					_stabilizationFramesRemaining--;
					_currentState = TrackingLossState.Stabilizing;
				}
				else
				{
					_currentState = TrackingLossState.Active;
				}
			}
			return _currentState;
		}

		public float GetFadeInterpolation(float deltaTime)
		{
			if (_currentState != TrackingLossState.Fading && _currentState != TrackingLossState.Stabilizing)
			{
				return 0f;
			}
			return 1f - Mathf.Exp((0f - FadeSpeed) * deltaTime);
		}

		public Quaternion ApplyFade(Quaternion currentRotation, float deltaTime)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: 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)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			float fadeInterpolation = GetFadeInterpolation(deltaTime);
			if (fadeInterpolation <= 0f)
			{
				return currentRotation;
			}
			return Quaternion.Slerp(currentRotation, Quaternion.identity, fadeInterpolation);
		}

		public void ClearRecenterFlag()
		{
			_needsRecenter = false;
		}

		public void Reset()
		{
			_framesWithoutData = 0;
			_secondsWithoutData = 0f;
			_stabilizationFramesRemaining = 0;
			_needsRecenter = false;
			_currentState = TrackingLossState.Active;
		}

		public void TriggerStabilization()
		{
			_stabilizationFramesRemaining = StabilizationFrames;
			_currentState = TrackingLossState.Stabilizing;
		}
	}
	public enum TrackingLossState
	{
		Active,
		Holding,
		Fading,
		Stabilizing
	}
	public static class ViewMatrixModifier
	{
		public static void ApplyHeadRotation(Camera cam, Quaternion headRotation)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)cam == (Object)null)
			{
				throw new ArgumentNullException("cam", "Camera cannot be null");
			}
			cam.ResetWorldToCameraMatrix();
			Matrix4x4 worldToCameraMatrix = cam.worldToCameraMatrix;
			Matrix4x4 val = Matrix4x4.Rotate(headRotation);
			cam.worldToCameraMatrix = val * worldToCameraMatrix;
		}

		public static void ApplyHeadRotation(Camera cam, float yaw, float pitch, float roll)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)cam == (Object)null)
			{
				throw new ArgumentNullException("cam", "Camera cannot be null");
			}
			Quaternion headRotation = Quaternion.Euler(pitch, yaw, 0f - roll);
			ApplyHeadRotation(cam, headRotation);
		}

		public static void ApplyHeadRotationDecomposed(Camera cam, float yaw, float pitch, float roll)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: 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_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)cam == (Object)null)
			{
				throw new ArgumentNullException("cam", "Camera cannot be null");
			}
			Quaternion val = Quaternion.AngleAxis(yaw, Vector3.up);
			Quaternion val2 = Quaternion.Euler(pitch, 0f, roll);
			Quaternion rotation = ((Component)cam).transform.rotation;
			Matrix4x4 val3 = Matrix4x4.Rotate(Quaternion.Inverse(val * rotation * val2));
			Matrix4x4 val4 = Matrix4x4.Translate(-((Component)cam).transform.position);
			Matrix4x4 val5 = val3 * val4;
			val5.m20 = 0f - val5.m20;
			val5.m21 = 0f - val5.m21;
			val5.m22 = 0f - val5.m22;
			val5.m23 = 0f - val5.m23;
			cam.worldToCameraMatrix = val5;
		}

		public static void SyncMatrixToTransform(Camera cam)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)cam == (Object)null)
			{
				throw new ArgumentNullException("cam", "Camera cannot be null");
			}
			Matrix4x4 localToWorldMatrix = ((Component)cam).transform.localToWorldMatrix;
			Matrix4x4 inverse = ((Matrix4x4)(ref localToWorldMatrix)).inverse;
			inverse.m20 = 0f - inverse.m20;
			inverse.m21 = 0f - inverse.m21;
			inverse.m22 = 0f - inverse.m22;
			inverse.m23 = 0f - inverse.m23;
			cam.worldToCameraMatrix = inverse;
		}

		public static void Reset(Camera cam)
		{
			if ((Object)(object)cam == (Object)null)
			{
				throw new ArgumentNullException("cam", "Camera cannot be null");
			}
			cam.ResetWorldToCameraMatrix();
		}

		public static Quaternion GetAppliedRotation(Camera cam)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)cam == (Object)null)
			{
				throw new ArgumentNullException("cam", "Camera cannot be null");
			}
			Matrix4x4 worldToCameraMatrix = cam.worldToCameraMatrix;
			cam.ResetWorldToCameraMatrix();
			Matrix4x4 worldToCameraMatrix2 = cam.worldToCameraMatrix;
			cam.worldToCameraMatrix = worldToCameraMatrix;
			Matrix4x4 val = worldToCameraMatrix * ((Matrix4x4)(ref worldToCameraMatrix2)).inverse;
			return ((Matrix4x4)(ref val)).rotation;
		}
	}
}
namespace CameraUnlock.Core.Unity.Rendering
{
	public delegate bool ReticlePositionProvider(out float screenX, out float screenY);
	public enum ReticleStyle
	{
		Dot,
		Circle
	}
	public sealed class IMGUIReticle : MonoBehaviour
	{
		private ReticlePositionProvider _positionProvider;

		private Texture2D _reticleTexture;

		private const int ReferenceHeight = 1080;

		private int _baseSizeAt1080p = 4;

		private int _thicknessAt1080p = 2;

		private int _currentTextureSize;

		private int _currentThickness;

		private int _lastScreenHeight;

		private Color _reticleColor = Color.white;

		private Color _outlineColor = new Color(0f, 0f, 0f, 0f);

		private int _outlineWidthAt1080p;

		private int _currentOutlineWidth;

		private bool _isVisible = true;

		private ReticleStyle _style;

		public int BaseSizeAt1080p
		{
			get
			{
				return _baseSizeAt1080p;
			}
			set
			{
				if (value != _baseSizeAt1080p)
				{
					_baseSizeAt1080p = Mathf.Max(1, value);
					RecreateTexture();
				}
			}
		}

		public Color ReticleColor
		{
			get
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				return _reticleColor;
			}
			set
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				if (value != _reticleColor)
				{
					_reticleColor = value;
					RecreateTexture();
				}
			}
		}

		public bool IsVisible
		{
			get
			{
				return _isVisible;
			}
			set
			{
				_isVisible = value;
			}
		}

		public ReticleStyle Style
		{
			get
			{
				return _style;
			}
			set
			{
				if (value != _style)
				{
					_style = value;
					RecreateTexture();
				}
			}
		}

		public int ThicknessAt1080p
		{
			get
			{
				return _thicknessAt1080p;
			}
			set
			{
				if (value != _thicknessAt1080p)
				{
					_thicknessAt1080p = Mathf.Max(1, value);
					RecreateTexture();
				}
			}
		}

		public Color OutlineColor
		{
			get
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				return _outlineColor;
			}
			set
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				if (value != _outlineColor)
				{
					_outlineColor = value;
					RecreateTexture();
				}
			}
		}

		public int OutlineWidthAt1080p
		{
			get
			{
				return _outlineWidthAt1080p;
			}
			set
			{
				if (value != _outlineWidthAt1080p)
				{
					_outlineWidthAt1080p = Mathf.Max(0, value);
					RecreateTexture();
				}
			}
		}

		public void Initialize(ReticlePositionProvider positionProvider)
		{
			_positionProvider = positionProvider;
			UpdateTextureForResolution();
		}

		public void InitializeWithOffset(Func<Vector2> getOffset, Func<bool> shouldDraw = null)
		{
			_positionProvider = delegate(out float x, out float y)
			{
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				//IL_003e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0053: Unknown result type (might be due to invalid IL or missing references)
				if (shouldDraw != null && !shouldDraw())
				{
					x = 0f;
					y = 0f;
					return false;
				}
				Vector2 val = getOffset();
				x = (float)Screen.width * 0.5f + val.x;
				y = (float)Screen.height * 0.5f + val.y;
				return true;
			};
			UpdateTextureForResolution();
		}

		private int ComputeScaledSize()
		{
			float num = (float)Screen.height / 1080f;
			int num2 = Mathf.RoundToInt((float)(_baseSizeAt1080p + _outlineWidthAt1080p * 2) * num);
			return Mathf.Max(2, num2);
		}

		private int ComputeScaledOutlineWidth()
		{
			if (_outlineWidthAt1080p <= 0)
			{
				return 0;
			}
			float num = (float)Screen.height / 1080f;
			int num2 = Mathf.RoundToInt((float)_outlineWidthAt1080p * num);
			return Mathf.Max(1, num2);
		}

		private int ComputeScaledThickness()
		{
			float num = (float)Screen.height / 1080f;
			int num2 = Mathf.RoundToInt((float)_thicknessAt1080p * num);
			return Mathf.Max(1, num2);
		}

		private void UpdateTextureForResolution()
		{
			int num = ComputeScaledSize();
			int num2 = ComputeScaledThickness();
			int num3 = ComputeScaledOutlineWidth();
			if ((Object)(object)_reticleTexture == (Object)null || num != _currentTextureSize || num2 != _currentThickness || num3 != _currentOutlineWidth || Screen.height != _lastScreenHeight)
			{
				_currentTextureSize = num;
				_currentThickness = num2;
				_currentOutlineWidth = num3;
				_lastScreenHeight = Screen.height;
				RecreateTexture();
			}
		}

		private void RecreateTexture()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_0305: Unknown result type (might be due to invalid IL or missing references)
			//IL_030b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0312: Unknown result type (might be due to invalid IL or missing references)
			//IL_0317: Unknown result type (might be due to invalid IL or missing references)
			//IL_032e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0330: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_reticleTexture != (Object)null)
			{
				Object.Destroy((Object)(object)_reticleTexture);
				_reticleTexture = null;
			}
			int num = _currentTextureSize;
			if (num < 2)
			{
				num = 2;
			}
			_reticleTexture = new Texture2D(num, num, (TextureFormat)4, false);
			_reticleTexture.filterMode = (FilterMode)1;
			Color val = default(Color);
			((Color)(ref val))..ctor(0f, 0f, 0f, 0f);
			Color[] array = (Color[])(object)new Color[num * num];
			for (int i = 0; i < array.Length; i++)
			{
				array[i] = val;
			}
			float num2 = (float)(num - 1) * 0.5f;
			float num3 = (float)num * 0.5f;
			float num4 = _currentOutlineWidth;
			float num5 = num3 - num4;
			if (num5 < 0f)
			{
				num5 = 0f;
			}
			if (_style == ReticleStyle.Dot)
			{
				for (int j = 0; j < num; j++)
				{
					for (int k = 0; k < num; k++)
					{
						float num6 = (float)k - num2;
						float num7 = (float)j - num2;
						float num8 = Mathf.Sqrt(num6 * num6 + num7 * num7);
						if (!(num8 > num3))
						{
							float num9 = Mathf.Clamp01(num3 - num8 + 0.5f);
							if (num4 > 0f && num8 > num5)
							{
								float num10 = Mathf.Clamp01(num8 - num5 + 0.5f);
								Color val2 = Color.Lerp(_reticleColor, _outlineColor, num10);
								val2.a *= num9;
								array[j * num + k] = val2;
							}
							else
							{
								Color reticleColor = _reticleColor;
								reticleColor.a *= num9;
								array[j * num + k] = reticleColor;
							}
						}
					}
				}
			}
			else
			{
				float num11 = _currentThickness;
				float num12 = num5 - num11;
				if (num12 < 0f)
				{
					num12 = 0f;
				}
				for (int l = 0; l < num; l++)
				{
					for (int m = 0; m < num; m++)
					{
						float num13 = (float)m - num2;
						float num14 = (float)l - num2;
						float num15 = Mathf.Sqrt(num13 * num13 + num14 * num14);
						if (num4 > 0f && num15 > num5 && num15 <= num3)
						{
							float num16 = Mathf.Clamp01(num3 - num15 + 0.5f);
							float num17 = Mathf.Clamp01(num15 - num5 + 0.5f);
							Color val3 = Color.Lerp(_reticleColor, _outlineColor, num17);
							val3.a *= num16;
							array[l * num + m] = val3;
						}
						else if (num15 >= num12 && num15 <= num5)
						{
							float num18 = Mathf.Clamp01(num5 - num15 + 0.5f);
							float num19 = Mathf.Clamp01(num15 - num12 + 0.5f);
							float num20 = num18 * num19;
							if (num20 > 0f)
							{
								Color reticleColor2 = _reticleColor;
								reticleColor2.a *= num20;
								array[l * num + m] = reticleColor2;
							}
						}
						else if (num4 > 0f && num15 < num12 && num15 >= num12 - num4)
						{
							float num21 = Mathf.Clamp01(num12 - num15 + 0.5f);
							float num22 = Mathf.Clamp01(num15 - (num12 - num4) + 0.5f);
							Color val4 = Color.Lerp(_reticleColor, _outlineColor, num21);
							val4.a *= num22;
							array[l * num + m] = val4;
						}
					}
				}
			}
			_reticleTexture.SetPixels(array);
			_reticleTexture.Apply();
		}

		private void OnGUI()
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			if (_isVisible && _positionProvider != null)
			{
				UpdateTextureForResolution();
				if (!((Object)(object)_reticleTexture == (Object)null) && _positionProvider(out var screenX, out var screenY))
				{
					float num = (float)Screen.height - screenY;
					int currentTextureSize = _currentTextureSize;
					GUI.DrawTexture(new Rect(screenX - (float)currentTextureSize * 0.5f, num - (float)currentTextureSize * 0.5f, (float)currentTextureSize, (float)currentTextureSize), (Texture)(object)_reticleTexture);
				}
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)_reticleTexture != (Object)null)
			{
				Object.Destroy((Object)(object)_reticleTexture);
				_reticleTexture = null;
			}
		}
	}
	public static class RenderPipelineHelper
	{
		private static bool _isRegistered;

		private static bool _usingSRP;

		private static CameraCallback _legacyPreRender;

		private static CameraCallback _legacyPostRender;

		private static object _srpPreRenderDelegate;

		private static object _srpPostRenderDelegate;

		private static bool _srpCheckDone;

		private static bool _srpAvailable;

		private static Action<Camera> _storedPreRender;

		private static Action<Camera> _storedPostRender;

		public static bool IsSRP
		{
			get
			{
				if (!_srpCheckDone)
				{
					_srpAvailable = CheckSRPAvailable();
					_srpCheckDone = true;
				}
				if (!_srpAvailable)
				{
					return false;
				}
				Type type = Type.GetType("UnityEngine.Rendering.GraphicsSettings, UnityEngine.CoreModule");
				if (type == null)
				{
					type = Type.GetType("UnityEngine.Rendering.GraphicsSettings, UnityEngine");
				}
				if (type != null)
				{
					PropertyInfo property = type.GetProperty("currentRenderPipeline", BindingFlags.Static | BindingFlags.Public);
					if (property != null)
					{
						return property.GetValue(null, null) != null;
					}
				}
				return false;
			}
		}

		public static bool IsRegistered => _isRegistered;

		public static void RegisterCallbacks(Action<Camera> onPreRender, Action<Camera> onPostRender)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			//

plugins\PeakHeadTracking.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using CameraUnlock.Core.Data;
using CameraUnlock.Core.Math;
using CameraUnlock.Core.Processing;
using CameraUnlock.Core.Protocol;
using CameraUnlock.Core.Unity.Extensions;
using CameraUnlock.Core.Unity.Rendering;
using CameraUnlock.Core.Unity.Tracking;
using HarmonyLib;
using PeakHeadTracking.Camera;
using PeakHeadTracking.Config;
using PeakHeadTracking.Input;
using PeakHeadTracking.Patches;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("itsloopyo")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Head tracking mod for PEAK using CameraUnlock.Core")]
[assembly: AssemblyFileVersion("1.0.2.0")]
[assembly: AssemblyInformationalVersion("1.0.2+9d1b08eb7c5e924f0f25a1b75e2ca7ed5bf74e78")]
[assembly: AssemblyProduct("PeakHeadTracking")]
[assembly: AssemblyTitle("PeakHeadTracking")]
[assembly: AssemblyVersion("1.0.2.0")]
namespace PeakHeadTracking
{
	public static class GameTypeNames
	{
		private const string AssemblyName = "Assembly-CSharp";

		public const string Character = "Character, Assembly-CSharp";

		public const string CharacterAnimations = "CharacterAnimations, Assembly-CSharp";

		public const string GUIManager = "GUIManager, Assembly-CSharp";

		public const string LoadingScreenHandler = "LoadingScreenHandler, Assembly-CSharp";

		public const string CameraQuad = "CameraQuad";
	}
	[BepInPlugin("com.cameraunlock.peak.headtracking", "Peak Head Tracking", "1.0.2")]
	[BepInProcess("Peak.exe")]
	public class PeakHeadTrackingPlugin : BaseUnityPlugin
	{
		public const string PLUGIN_GUID = "com.cameraunlock.peak.headtracking";

		public const string PLUGIN_NAME = "Peak Head Tracking";

		public const string PLUGIN_VERSION = "1.0.2";

		internal static ManualLogSource Logger;

		private Harmony harmony;

		private GameObject trackingManagerObject;

		private ModConfiguration modConfig;

		private ConfigurationManager configManager;

		private ProfileManager profileManager;

		private OpenTrackReceiver coreReceiver;

		private TrackingProcessor processor;

		private PoseInterpolator interpolator;

		private CameraController cameraController;

		private HotkeyManager hotkeyManager;

		private PositionProcessor positionProcessor;

		private PositionInterpolator positionInterpolator;

		private bool destroyed;

		private void Awake()
		{
			Logger = ((BaseUnityPlugin)this).Logger;
			Logger.LogInfo((object)"Initializing Peak Head Tracking v1.0.2");
			try
			{
				InitializeConfiguration();
				CreateTrackingManager();
				InitializeHarmonyPatches();
				InitializeComponents();
				Logger.LogInfo((object)"Peak Head Tracking successfully loaded!");
			}
			catch (Exception arg)
			{
				Logger.LogError((object)string.Format("Failed to initialize {0}: {1}", "Peak Head Tracking", arg));
				throw;
			}
		}

		private void InitializeConfiguration()
		{
			Logger.LogDebug((object)"Initializing configuration...");
			configManager = ConfigurationManager.Instance;
			configManager.Initialize(((BaseUnityPlugin)this).Config);
			modConfig = configManager.Config;
			profileManager = configManager.Profiles;
			configManager.ProfileChanged += OnProfileChanged;
			Logger.LogDebug((object)("Configuration loaded - Profile: " + profileManager.GetActiveProfileName() + ", " + $"UDP Port: {modConfig.UdpPort.Value}, " + $"Tracking Enabled: {modConfig.TrackingEnabled.Value}"));
		}

		private void CreateTrackingManager()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			Logger.LogDebug((object)"Creating tracking manager GameObject...");
			trackingManagerObject = new GameObject("PeakHeadTrackingManager");
			Object.DontDestroyOnLoad((Object)(object)trackingManagerObject);
			trackingManagerObject.hideFlags = (HideFlags)61;
		}

		private void InitializeHarmonyPatches()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			Logger.LogDebug((object)"Initializing Harmony patches...");
			harmony = new Harmony("com.cameraunlock.peak.headtracking");
			harmony.PatchAll();
			IEnumerable<MethodBase> patchedMethods = harmony.GetPatchedMethods();
			int num = 0;
			foreach (MethodBase item in patchedMethods)
			{
				num++;
				Logger.LogDebug((object)("Patched: " + item.DeclaringType?.Name + "." + item.Name));
			}
			Logger.LogInfo((object)$"Applied {num} Harmony patches");
		}

		private void InitializeComponents()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Expected O, but got Unknown
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Expected O, but got Unknown
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Expected O, but got Unknown
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Expected O, but got Unknown
			Logger.LogDebug((object)"Initializing components...");
			coreReceiver = new OpenTrackReceiver();
			coreReceiver.Log = delegate(string msg)
			{
				Logger.LogInfo((object)msg);
			};
			processor = new TrackingProcessor
			{
				SmoothingFactor = modConfig.Smoothing.Value,
				Sensitivity = new SensitivitySettings(modConfig.YawSensitivity.Value, modConfig.PitchSensitivity.Value, modConfig.RollSensitivity.Value, false, false, false),
				Deadzone = (DeadzoneSettings)(modConfig.EnableDeadzone.Value ? new DeadzoneSettings(modConfig.DeadzoneYaw.Value, modConfig.DeadzonePitch.Value, modConfig.DeadzoneRoll.Value) : DeadzoneSettings.None)
			};
			interpolator = new PoseInterpolator();
			cameraController = trackingManagerObject.AddComponent<CameraController>();
			cameraController.Initialize(modConfig, coreReceiver, processor, interpolator);
			positionProcessor = new PositionProcessor
			{
				Settings = new PositionSettings(modConfig.PositionSensitivityX.Value, modConfig.PositionSensitivityY.Value, modConfig.PositionSensitivityZ.Value, modConfig.PositionLimitX.Value, modConfig.PositionLimitY.Value, 0.1f, modConfig.PositionLimitZ.Value, modConfig.PositionSmoothing.Value, true, false, false)
			};
			positionInterpolator = new PositionInterpolator();
			CameraPatches.SetReceiver(coreReceiver);
			CameraPatches.SetPositionProcessors(positionProcessor, positionInterpolator, modConfig.PositionEnabled);
			CameraPatches.SetNearClipConfig(modConfig.NearClipOverride);
			CameraPatches.SetReticleConfig(modConfig.ShowReticle);
			hotkeyManager = trackingManagerObject.AddComponent<HotkeyManager>();
			hotkeyManager.Initialize(modConfig, cameraController, coreReceiver);
			SetupConfigurationCallbacks();
			Logger.LogDebug((object)"All components initialized");
		}

		private void Start()
		{
			Logger.LogDebug((object)"Plugin Start() called");
			if (modConfig.TrackingEnabled.Value)
			{
				coreReceiver.Start(modConfig.UdpPort.Value);
				cameraController.SetTrackingEnabled(enabled: true);
				Logger.LogInfo((object)"Head tracking started");
			}
			else
			{
				Logger.LogInfo((object)"Head tracking disabled by configuration");
			}
		}

		private void SetupConfigurationCallbacks()
		{
			configManager.RegisterSettingChangeCallback("UdpPort", delegate
			{
				Logger.LogInfo((object)$"UDP Port changed to {modConfig.UdpPort.Value}, restarting receiver...");
				OpenTrackReceiver obj2 = coreReceiver;
				if (obj2 != null)
				{
					obj2.Dispose();
				}
				OpenTrackReceiver obj3 = coreReceiver;
				if (obj3 != null)
				{
					obj3.Start(modConfig.UdpPort.Value);
				}
			});
			configManager.RegisterSettingChangeCallback("TrackingEnabled", delegate
			{
				if (modConfig.TrackingEnabled.Value)
				{
					if (!coreReceiver.IsReceiving && !coreReceiver.IsFailed)
					{
						coreReceiver.Start(modConfig.UdpPort.Value);
					}
					cameraController?.SetTrackingEnabled(enabled: true);
					Logger.LogInfo((object)"Tracking enabled via configuration");
				}
				else
				{
					OpenTrackReceiver obj = coreReceiver;
					if (obj != null)
					{
						obj.Dispose();
					}
					cameraController?.SetTrackingEnabled(enabled: false);
					Logger.LogInfo((object)"Tracking disabled via configuration");
				}
			});
			configManager.RegisterSettingChangeCallback("UpdateRate", delegate
			{
				Logger.LogDebug((object)$"Update rate changed to {modConfig.UpdateRate.Value} Hz");
			});
		}

		private void OnProfileChanged(object sender, string profileName)
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			Logger.LogInfo((object)("Switched to profile: " + profileName));
			if (coreReceiver != null)
			{
				coreReceiver.Dispose();
				coreReceiver.Start(modConfig.UdpPort.Value);
			}
			processor.Sensitivity = new SensitivitySettings(modConfig.YawSensitivity.Value, modConfig.PitchSensitivity.Value, modConfig.RollSensitivity.Value, false, false, false);
			processor.SmoothingFactor = modConfig.Smoothing.Value;
			processor.Deadzone = (DeadzoneSettings)(modConfig.EnableDeadzone.Value ? new DeadzoneSettings(modConfig.DeadzoneYaw.Value, modConfig.DeadzonePitch.Value, modConfig.DeadzoneRoll.Value) : DeadzoneSettings.None);
			cameraController?.Initialize(modConfig, coreReceiver, processor, interpolator);
			hotkeyManager?.Initialize(modConfig, cameraController, coreReceiver);
			if (modConfig.TrackingEnabled.Value)
			{
				cameraController?.SetTrackingEnabled(enabled: true);
			}
		}

		private void OnDestroy()
		{
			if (!destroyed)
			{
				destroyed = true;
				Logger.LogInfo((object)"Shutting down Peak Head Tracking...");
				CameraPatches.UnregisterCameraCallback();
				Harmony obj = harmony;
				if (obj != null)
				{
					obj.UnpatchSelf();
				}
				harmony = null;
				if ((Object)(object)trackingManagerObject != (Object)null)
				{
					Object.DestroyImmediate((Object)(object)trackingManagerObject);
					trackingManagerObject = null;
				}
				if (coreReceiver != null)
				{
					coreReceiver.Dispose();
					coreReceiver = null;
				}
				CameraPatches.SetReceiver(null);
				if (configManager != null)
				{
					configManager.ProfileChanged -= OnProfileChanged;
				}
				configManager?.Cleanup();
				configManager = null;
				modConfig = null;
				Logger.LogInfo((object)"Cleanup complete");
			}
		}

		private void OnApplicationQuit()
		{
			OnDestroy();
		}
	}
	public static class ReflectionUtils
	{
		public static Func<TResult> CreateStaticFieldGetter<TResult>(FieldInfo field)
		{
			return Expression.Lambda<Func<TResult>>(Expression.Convert(Expression.Field(null, field), typeof(TResult)), Array.Empty<ParameterExpression>()).Compile();
		}

		public static Func<object, TResult> CreateInstanceFieldGetter<TResult>(Type instanceType, FieldInfo field)
		{
			ParameterExpression parameterExpression = Expression.Parameter(typeof(object), "instance");
			return Expression.Lambda<Func<object, TResult>>(Expression.Convert(Expression.Field(Expression.Convert(parameterExpression, instanceType), field), typeof(TResult)), new ParameterExpression[1] { parameterExpression }).Compile();
		}

		public static Func<TResult> CreateStaticPropertyGetter<TResult>(PropertyInfo property)
		{
			return Expression.Lambda<Func<TResult>>(Expression.Convert(Expression.Property(null, property), typeof(TResult)), Array.Empty<ParameterExpression>()).Compile();
		}
	}
}
namespace PeakHeadTracking.Patches
{
	public static class CameraPatches
	{
		private static OpenTrackReceiver receiver;

		private static PositionProcessor positionProcessor;

		private static PositionInterpolator positionInterpolator;

		private static ConfigEntry<bool> positionEnabledConfig;

		private static ConfigEntry<bool> showReticleConfig;

		private static ConfigEntry<float> nearClipConfig;

		private static float storedNearClipPlane;

		private static float currentYaw = 0f;

		private static float currentPitch = 0f;

		private static bool headTrackingEnabled = false;

		private static bool hasLoggedFirstApplication = false;

		private static volatile float processedYaw = 0f;

		private static volatile float processedPitch = 0f;

		private static volatile float processedRoll = 0f;

		private static bool callbackRegistered = false;

		private static bool matrixModifiedThisFrame = false;

		private static int lastDiagnosticFrame = -1;

		private const int DiagnosticLogInterval = 300;

		public static float CurrentYaw => currentYaw;

		public static float CurrentPitch => currentPitch;

		internal static float ProcessedYaw => processedYaw;

		internal static float ProcessedPitch => processedPitch;

		internal static float ProcessedRoll => processedRoll;

		public static void SetReceiver(OpenTrackReceiver coreReceiver)
		{
			receiver = coreReceiver;
		}

		public static void SetPositionProcessors(PositionProcessor posProccesor, PositionInterpolator posInterp, ConfigEntry<bool> posEnabled)
		{
			positionProcessor = posProccesor;
			positionInterpolator = posInterp;
			positionEnabledConfig = posEnabled;
		}

		public static void SetNearClipConfig(ConfigEntry<float> config)
		{
			nearClipConfig = config;
		}

		public static void SetReticleConfig(ConfigEntry<bool> config)
		{
			showReticleConfig = config;
		}

		public static void RecenterPosition()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			if (positionProcessor != null && receiver != null)
			{
				positionProcessor.SetCenter(receiver.GetLatestPosition());
				PositionInterpolator obj = positionInterpolator;
				if (obj != null)
				{
					obj.Reset();
				}
			}
		}

		public static void SetHeadTrackingInput(float yaw, float pitch)
		{
			currentYaw = yaw;
			currentPitch = pitch;
		}

		public static void SetProcessedRotation(float yaw, float pitch, float roll)
		{
			processedYaw = yaw;
			processedPitch = pitch;
			processedRoll = roll;
			currentYaw = yaw;
			currentPitch = pitch;
		}

		public static void SetHeadTrackingEnabled(bool enabled)
		{
			headTrackingEnabled = enabled;
			if (enabled && !callbackRegistered)
			{
				RegisterCameraCallback();
			}
			if (!enabled)
			{
				ReticleCompensation.ResetReticlePosition();
			}
		}

		public static void RegisterCameraCallback()
		{
			if (callbackRegistered)
			{
				ManualLogSource logger = PeakHeadTrackingPlugin.Logger;
				if (logger != null)
				{
					logger.LogWarning((object)"[RegisterCameraCallback] Already registered, skipping");
				}
				return;
			}
			ManualLogSource logger2 = PeakHeadTrackingPlugin.Logger;
			if (logger2 != null)
			{
				logger2.LogDebug((object)("Render pipeline: " + (RenderPipelineHelper.IsSRP ? "SRP" : "Legacy")));
			}
			RenderPipelineHelper.RegisterCallbacks((Action<Camera>)OnPreRender, (Action<Camera>)OnPostRender);
			callbackRegistered = true;
			ManualLogSource logger3 = PeakHeadTrackingPlugin.Logger;
			if (logger3 != null)
			{
				logger3.LogDebug((object)"Camera render callback registered");
			}
		}

		public static void UnregisterCameraCallback()
		{
			if (callbackRegistered)
			{
				RenderPipelineHelper.UnregisterCallbacks();
				callbackRegistered = false;
				ManualLogSource logger = PeakHeadTrackingPlugin.Logger;
				if (logger != null)
				{
					logger.LogDebug((object)"Camera render callback unregistered");
				}
			}
		}

		public static Vector2 GetHeadTrackingInput()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			return new Vector2(currentYaw, currentPitch);
		}

		public static bool IsHeadTrackingEnabled()
		{
			return headTrackingEnabled;
		}

		private static void OnPreRender(Camera cam)
		{
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			Camera main = Camera.main;
			if ((Object)(object)main == (Object)null)
			{
				LogDiagnostic("[HeadTracking] Camera.main is null - waiting for camera");
			}
			else
			{
				if ((Object)(object)cam != (Object)(object)main || !headTrackingEnabled)
				{
					return;
				}
				if (receiver == null)
				{
					LogDiagnostic("[HeadTracking] ERROR: Receiver is null - tracking disabled");
					return;
				}
				if (GameplayStateDetection.ShouldSkipHeadTracking())
				{
					ReticleCompensation.ResetReticlePosition();
					return;
				}
				float num = processedYaw;
				float num2 = processedPitch;
				float num3 = processedRoll;
				if (Mathf.Abs(num) < 0.1f && Mathf.Abs(num2) < 0.1f && Mathf.Abs(num3) < 0.1f)
				{
					return;
				}
				ViewMatrixModifier.ApplyHeadRotation(cam, num, 0f - num2, num3);
				matrixModifiedThisFrame = true;
				if (positionProcessor != null && positionEnabledConfig != null && positionEnabledConfig.Value && receiver != null)
				{
					PositionData latestPosition = receiver.GetLatestPosition();
					PositionData val = positionInterpolator.Update(latestPosition, Time.deltaTime);
					Quat4 val2 = QuaternionUtils.FromYawPitchRoll(num, 0f - num2, num3);
					Vec3 val3 = positionProcessor.Process(val, val2, Time.deltaTime);
					cam.worldToCameraMatrix = Matrix4x4.Translate(-UnityTypeExtensions.ToUnity(val3)) * cam.worldToCameraMatrix;
				}
				storedNearClipPlane = cam.nearClipPlane;
				if (nearClipConfig != null && cam.nearClipPlane < nearClipConfig.Value)
				{
					cam.nearClipPlane = nearClipConfig.Value;
				}
				if (showReticleConfig != null && showReticleConfig.Value && ReticleCompensation.CanUpdateReticle())
				{
					ReticleCompensation.UpdateReticlePosition(cam);
				}
				else
				{
					ReticleCompensation.ResetReticlePosition();
				}
				if (!hasLoggedFirstApplication)
				{
					ManualLogSource logger = PeakHeadTrackingPlugin.Logger;
					if (logger != null)
					{
						logger.LogInfo((object)$"[ApplyHeadTracking] SUCCESS! Applied via ViewMatrixModifier: Yaw={num:F2}, Pitch={num2:F2}, Roll={num3:F2}");
					}
					hasLoggedFirstApplication = true;
				}
			}
		}

		private static void OnPostRender(Camera cam)
		{
			Camera main = Camera.main;
			if (!((Object)(object)main == (Object)null) && !((Object)(object)cam != (Object)(object)main) && matrixModifiedThisFrame)
			{
				matrixModifiedThisFrame = false;
				ViewMatrixModifier.Reset(cam);
				cam.nearClipPlane = storedNearClipPlane;
			}
		}

		private static void LogDiagnostic(string message)
		{
			int frameCount = Time.frameCount;
			if (frameCount - lastDiagnosticFrame >= 300)
			{
				lastDiagnosticFrame = frameCount;
				ManualLogSource logger = PeakHeadTrackingPlugin.Logger;
				if (logger != null)
				{
					logger.LogWarning((object)message);
				}
			}
		}
	}
	[HarmonyPatch]
	public static class CameraQuadPatches
	{
		private static bool patchActive;

		private static Quaternion storedRotation;

		[HarmonyTargetMethod]
		public static MethodBase TargetMethod()
		{
			try
			{
				Type type = AccessTools.TypeByName("CameraQuad");
				if (type == null)
				{
					ManualLogSource logger = PeakHeadTrackingPlugin.Logger;
					if (logger != null)
					{
						logger.LogWarning((object)"[CameraQuadPatch] CameraQuad type not found - patch will not be applied");
					}
					return null;
				}
				MethodInfo methodInfo = AccessTools.Method(type, "LateUpdate", (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					ManualLogSource logger2 = PeakHeadTrackingPlugin.Logger;
					if (logger2 != null)
					{
						logger2.LogWarning((object)"[CameraQuadPatch] CameraQuad.LateUpdate method not found");
					}
					return null;
				}
				patchActive = true;
				ManualLogSource logger3 = PeakHeadTrackingPlugin.Logger;
				if (logger3 != null)
				{
					logger3.LogInfo((object)"[CameraQuadPatch] Successfully targeting CameraQuad.LateUpdate");
				}
				return methodInfo;
			}
			catch (Exception ex)
			{
				ManualLogSource logger4 = PeakHeadTrackingPlugin.Logger;
				if (logger4 != null)
				{
					logger4.LogError((object)("[CameraQuadPatch] Error finding target method: " + ex.Message));
				}
				return null;
			}
		}

		[HarmonyPrefix]
		public static void LateUpdate_Prefix()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			if (patchActive && CameraPatches.IsHeadTrackingEnabled())
			{
				Camera main = Camera.main;
				if (!((Object)(object)main == (Object)null))
				{
					float processedYaw = CameraPatches.ProcessedYaw;
					float processedPitch = CameraPatches.ProcessedPitch;
					float processedRoll = CameraPatches.ProcessedRoll;
					storedRotation = ((Component)main).transform.rotation;
					((Component)main).transform.rotation = CameraRotationComposer.ComposeAdditive(storedRotation, processedYaw, processedPitch, processedRoll);
				}
			}
		}

		[HarmonyPostfix]
		public static void LateUpdate_Postfix()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if (patchActive && CameraPatches.IsHeadTrackingEnabled())
			{
				Camera main = Camera.main;
				if (!((Object)(object)main == (Object)null))
				{
					((Component)main).transform.rotation = storedRotation;
				}
			}
		}
	}
	internal static class GameplayStateDetection
	{
		private static bool loadingReflectionInitialized = false;

		private static Func<bool> getIsLoading;

		private static Type characterType;

		private static bool gameplayReflectionInitialized = false;

		private static Func<object> getLocalCharacter;

		private static Func<object> getGUIManagerInstance;

		private static Func<object, object> getPauseMenu;

		private static string cachedSceneName = "";

		private static bool isOnTitleScene = false;

		private const string TitleSceneName = "Title";

		private static void UpdateSceneCache()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			Scene activeScene = SceneManager.GetActiveScene();
			string name = ((Scene)(ref activeScene)).name;
			if (name != cachedSceneName)
			{
				cachedSceneName = name;
				isOnTitleScene = name == "Title";
				ReticleCompensation.InvalidateCache();
			}
		}

		internal static bool ShouldSkipHeadTracking()
		{
			UpdateSceneCache();
			if (isOnTitleScene)
			{
				return true;
			}
			if (!gameplayReflectionInitialized)
			{
				gameplayReflectionInitialized = true;
				characterType = Type.GetType("Character, Assembly-CSharp");
				if (characterType != null)
				{
					FieldInfo field = characterType.GetField("localCharacter", BindingFlags.Static | BindingFlags.Public);
					if (field != null)
					{
						getLocalCharacter = ReflectionUtils.CreateStaticFieldGetter<object>(field);
					}
				}
				if (ReticleCompensation.GUIManagerType != null && ReticleCompensation.GUIManagerInstanceField != null)
				{
					getGUIManagerInstance = ReflectionUtils.CreateStaticFieldGetter<object>(ReticleCompensation.GUIManagerInstanceField);
					FieldInfo field2 = ReticleCompensation.GUIManagerType.GetField("pauseMenu", BindingFlags.Instance | BindingFlags.Public);
					if (field2 != null)
					{
						getPauseMenu = ReflectionUtils.CreateInstanceFieldGetter<object>(ReticleCompensation.GUIManagerType, field2);
					}
				}
				ManualLogSource logger = PeakHeadTrackingPlugin.Logger;
				if (logger != null)
				{
					logger.LogInfo((object)$"[GameplayDetection] Compiled delegates - localCharacter: {getLocalCharacter != null}, guiInstance: {getGUIManagerInstance != null}, pauseMenu: {getPauseMenu != null}");
				}
			}
			if (getLocalCharacter == null)
			{
				throw new InvalidOperationException("Cannot detect gameplay state: getLocalCharacter delegate was not compiled during reflection setup");
			}
			if (getLocalCharacter() == null)
			{
				return true;
			}
			if (getGUIManagerInstance != null && getPauseMenu != null)
			{
				object obj = getGUIManagerInstance();
				if (obj != null)
				{
					object obj2 = getPauseMenu(obj);
					GameObject val = (GameObject)((obj2 is GameObject) ? obj2 : null);
					if (val != null && val.activeSelf)
					{
						return true;
					}
				}
			}
			if (!loadingReflectionInitialized)
			{
				loadingReflectionInitialized = true;
				Type type = Type.GetType("LoadingScreenHandler, Assembly-CSharp");
				if (type != null)
				{
					PropertyInfo property = type.GetProperty("loading", BindingFlags.Static | BindingFlags.Public);
					if (property != null)
					{
						getIsLoading = ReflectionUtils.CreateStaticPropertyGetter<bool>(property);
					}
				}
			}
			if (getIsLoading != null && getIsLoading())
			{
				return true;
			}
			return false;
		}
	}
	[HarmonyPatch]
	public static class HeadRotationPatches
	{
		private static readonly int AN_LOOK_Y = Animator.StringToHash("Look Y");

		private static readonly int AN_LOOK_X = Animator.StringToHash("Look X");

		private const float DegreesNormalizationFactor = 90f;

		private static Type characterAnimationsType;

		private static Type characterType;

		private static Func<object, object> getCharacterFromAnimations;

		private static Func<object> getLocalCharacter;

		private static Func<object, object> getRefsFromCharacter;

		private static Func<object, Animator> getAnimatorFromRefs;

		private static bool reflectionInitialized = false;

		private static bool reflectionFailed = false;

		private static bool hasLoggedSuccess = false;

		[HarmonyTargetMethod]
		public static MethodBase TargetMethod()
		{
			characterAnimationsType = Type.GetType("CharacterAnimations, Assembly-CSharp");
			if (characterAnimationsType == null)
			{
				throw new TypeLoadException("[HeadRotation] CharacterAnimations type not found in Assembly-CSharp");
			}
			MethodInfo? method = characterAnimationsType.GetMethod("Update", BindingFlags.Instance | BindingFlags.NonPublic);
			if (method == null)
			{
				throw new MissingMethodException("[HeadRotation] CharacterAnimations.Update method not found");
			}
			ManualLogSource logger = PeakHeadTrackingPlugin.Logger;
			if (logger != null)
			{
				logger.LogInfo((object)"[HeadRotation] Found target method: CharacterAnimations.Update");
				return method;
			}
			return method;
		}

		private static void InitializeReflection()
		{
			if (reflectionFailed)
			{
				throw new InvalidOperationException("HeadRotationPatches reflection initialization previously failed. Cannot proceed.");
			}
			if (!reflectionInitialized)
			{
				reflectionInitialized = true;
				if (characterAnimationsType == null)
				{
					characterAnimationsType = Type.GetType("CharacterAnimations, Assembly-CSharp");
				}
				if (characterAnimationsType == null)
				{
					reflectionFailed = true;
					throw new TypeLoadException("[HeadRotation] CharacterAnimations type not found in reflection init");
				}
				FieldInfo field = characterAnimationsType.GetField("character", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field == null)
				{
					reflectionFailed = true;
					throw new MissingFieldException("[HeadRotation] CharacterAnimations.character field not found");
				}
				characterType = Type.GetType("Character, Assembly-CSharp");
				if (characterType == null)
				{
					reflectionFailed = true;
					throw new TypeLoadException("[HeadRotation] Character type not found");
				}
				FieldInfo field2 = characterType.GetField("localCharacter", BindingFlags.Static | BindingFlags.Public);
				if (field2 == null)
				{
					reflectionFailed = true;
					throw new MissingFieldException("[HeadRotation] Character.localCharacter field not found");
				}
				FieldInfo field3 = characterType.GetField("refs", BindingFlags.Instance | BindingFlags.Public);
				if (field3 == null)
				{
					reflectionFailed = true;
					throw new MissingFieldException("[HeadRotation] Character.refs field not found");
				}
				Type fieldType = field3.FieldType;
				FieldInfo field4 = fieldType.GetField("animator", BindingFlags.Instance | BindingFlags.Public);
				if (field4 == null)
				{
					reflectionFailed = true;
					throw new MissingFieldException("[HeadRotation] CharacterRefs.animator field not found");
				}
				getCharacterFromAnimations = ReflectionUtils.CreateInstanceFieldGetter<object>(characterAnimationsType, field);
				getLocalCharacter = ReflectionUtils.CreateStaticFieldGetter<object>(field2);
				getRefsFromCharacter = ReflectionUtils.CreateInstanceFieldGetter<object>(characterType, field3);
				getAnimatorFromRefs = ReflectionUtils.CreateInstanceFieldGetter<Animator>(fieldType, field4);
				ManualLogSource logger = PeakHeadTrackingPlugin.Logger;
				if (logger != null)
				{
					logger.LogInfo((object)"[HeadRotation] Reflection initialized with compiled delegates");
				}
			}
		}

		[HarmonyPostfix]
		public static void Postfix(object __instance)
		{
			InitializeReflection();
			if (!CameraPatches.IsHeadTrackingEnabled())
			{
				return;
			}
			float currentYaw = CameraPatches.CurrentYaw;
			float currentPitch = CameraPatches.CurrentPitch;
			if (Mathf.Abs(currentYaw) < 0.1f && Mathf.Abs(currentPitch) < 0.1f)
			{
				return;
			}
			object obj = getCharacterFromAnimations(__instance);
			if (obj == null)
			{
				return;
			}
			object obj2 = getLocalCharacter();
			if (obj2 == null || obj != obj2)
			{
				return;
			}
			object obj3 = getRefsFromCharacter(obj2);
			if (obj3 == null)
			{
				return;
			}
			Animator val = getAnimatorFromRefs(obj3);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			float @float = val.GetFloat(AN_LOOK_X);
			float float2 = val.GetFloat(AN_LOOK_Y);
			float num = currentYaw / 90f;
			float num2 = currentPitch / 90f;
			float num3 = @float + num;
			float num4 = float2 - num2;
			val.SetFloat(AN_LOOK_X, num3);
			val.SetFloat(AN_LOOK_Y, num4);
			if (!hasLoggedSuccess)
			{
				ManualLogSource logger = PeakHeadTrackingPlugin.Logger;
				if (logger != null)
				{
					logger.LogInfo((object)$"[HeadRotation] SUCCESS! Modified animator Look params: LookX {@float:F2}->{num3:F2}, LookY {float2:F2}->{num4:F2}");
				}
				hasLoggedSuccess = true;
			}
		}
	}
	internal static class ReticleCompensation
	{
		private static Type guiManagerType;

		private static FieldInfo instanceField;

		private static bool reticleReflectionInitialized = false;

		private static Func<object> getGUIManagerInstance;

		private static Func<object, object> getReticleDefault;

		private static bool reticleParentFound = false;

		private static RectTransform reticleParentTransform;

		private static Canvas cachedReticleCanvas;

		private static float cachedCanvasScaleFactor = 1f;

		private static Func<object, object> getInteractName;

		private static Func<object, object> getInteractPromptPrimary;

		private static Func<object, object> getInteractPromptSecondary;

		private static Func<object, object> getInteractPromptHold;

		private static Func<object, object> getInteractPromptLunge;

		private static RectTransform[] interactTransforms;

		private static bool interactElementsFound = false;

		private static bool interactElementsSearched = false;

		internal static Type GUIManagerType => guiManagerType;

		internal static FieldInfo GUIManagerInstanceField => instanceField;

		internal static void InitializeReticleReflection()
		{
			if (reticleReflectionInitialized)
			{
				return;
			}
			reticleReflectionInitialized = true;
			guiManagerType = Type.GetType("GUIManager, Assembly-CSharp");
			if (guiManagerType == null)
			{
				throw new InvalidOperationException("[Reticle] GUIManager type not found - game version may be incompatible");
			}
			instanceField = guiManagerType.GetField("instance", BindingFlags.Static | BindingFlags.Public);
			FieldInfo field = guiManagerType.GetField("reticleDefault", BindingFlags.Instance | BindingFlags.Public);
			if (instanceField == null || field == null)
			{
				throw new InvalidOperationException("[Reticle] GUIManager required fields not found - game version may be incompatible");
			}
			getGUIManagerInstance = ReflectionUtils.CreateStaticFieldGetter<object>(instanceField);
			getReticleDefault = ReflectionUtils.CreateInstanceFieldGetter<object>(guiManagerType, field);
			string[] array = new string[5] { "interactName", "interactPromptPrimary", "interactPromptSecondary", "interactPromptHold", "interactPromptLunge" };
			Func<object, object>[] array2 = new Func<object, object>[array.Length];
			for (int i = 0; i < array.Length; i++)
			{
				FieldInfo field2 = guiManagerType.GetField(array[i], BindingFlags.Instance | BindingFlags.Public);
				if (field2 != null)
				{
					array2[i] = ReflectionUtils.CreateInstanceFieldGetter<object>(guiManagerType, field2);
				}
			}
			getInteractName = array2[0];
			getInteractPromptPrimary = array2[1];
			getInteractPromptSecondary = array2[2];
			getInteractPromptHold = array2[3];
			getInteractPromptLunge = array2[4];
			ManualLogSource logger = PeakHeadTrackingPlugin.Logger;
			if (logger != null)
			{
				logger.LogInfo((object)"[Reticle] Reflection initialized successfully");
			}
		}

		private static void FindReticleParent()
		{
			if (guiManagerType == null || (reticleParentFound && (Object)(object)reticleParentTransform != (Object)null))
			{
				return;
			}
			if (reticleParentFound)
			{
				ManualLogSource logger = PeakHeadTrackingPlugin.Logger;
				if (logger != null)
				{
					logger.LogInfo((object)"[Reticle] Cached reticle parent became invalid, re-finding...");
				}
				reticleParentFound = false;
				reticleParentTransform = null;
				cachedReticleCanvas = null;
				cachedCanvasScaleFactor = 1f;
			}
			object obj = getGUIManagerInstance();
			if (obj == null)
			{
				return;
			}
			object obj2 = getReticleDefault(obj);
			GameObject val = (GameObject)((obj2 is GameObject) ? obj2 : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Transform parent = val.transform.parent;
			if (!((Object)(object)parent != (Object)null))
			{
				return;
			}
			reticleParentTransform = ((Component)parent).GetComponent<RectTransform>();
			if ((Object)(object)reticleParentTransform != (Object)null)
			{
				reticleParentFound = true;
				cachedReticleCanvas = ((Component)reticleParentTransform).GetComponentInParent<Canvas>();
				if ((Object)(object)cachedReticleCanvas != (Object)null && cachedReticleCanvas.scaleFactor > 0f)
				{
					cachedCanvasScaleFactor = cachedReticleCanvas.scaleFactor;
				}
				else
				{
					cachedCanvasScaleFactor = 1f;
				}
				ManualLogSource logger2 = PeakHeadTrackingPlugin.Logger;
				if (logger2 != null)
				{
					logger2.LogInfo((object)$"[Reticle] Found reticle parent: {((Object)parent).name}, canvas scale: {cachedCanvasScaleFactor}");
				}
			}
		}

		private static void FindInteractElements()
		{
			if (interactElementsFound || interactElementsSearched || getInteractName == null || getGUIManagerInstance == null)
			{
				return;
			}
			interactElementsSearched = true;
			object obj = getGUIManagerInstance();
			if (obj == null)
			{
				interactElementsSearched = false;
				return;
			}
			Func<object, object>[] obj2 = new Func<object, object>[5] { getInteractName, getInteractPromptPrimary, getInteractPromptSecondary, getInteractPromptHold, getInteractPromptLunge };
			List<RectTransform> list = new List<RectTransform>();
			Func<object, object>[] array = obj2;
			foreach (Func<object, object> func in array)
			{
				if (func == null)
				{
					continue;
				}
				object obj3 = func(obj);
				GameObject val = (GameObject)((obj3 is GameObject) ? obj3 : null);
				if (!((Object)(object)val == (Object)null))
				{
					RectTransform component = val.GetComponent<RectTransform>();
					if ((Object)(object)component != (Object)null)
					{
						list.Add(component);
					}
				}
			}
			if (list.Count > 0)
			{
				interactTransforms = list.ToArray();
				interactElementsFound = true;
				ManualLogSource logger = PeakHeadTrackingPlugin.Logger;
				if (logger != null)
				{
					logger.LogInfo((object)$"[Reticle] Found {interactTransforms.Length} interact elements to compensate");
				}
			}
		}

		internal static bool CanUpdateReticle()
		{
			InitializeReticleReflection();
			FindReticleParent();
			if (reticleParentFound)
			{
				return (Object)(object)reticleParentTransform != (Object)null;
			}
			return false;
		}

		internal static void UpdateReticlePosition(Camera cam)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			if (!reticleParentFound || (Object)(object)reticleParentTransform == (Object)null)
			{
				throw new InvalidOperationException("Reticle parent transform not found. Caller must check CanUpdateReticle() before calling.");
			}
			Vector3 forward = ((Component)cam).transform.forward;
			Vector2 anchoredPosition = CanvasCompensation.CalculateAimScreenOffset(cam, forward, cachedCanvasScaleFactor);
			reticleParentTransform.anchoredPosition = anchoredPosition;
			FindInteractElements();
			if (!interactElementsFound)
			{
				return;
			}
			RectTransform[] array = interactTransforms;
			foreach (RectTransform val in array)
			{
				if ((Object)(object)val != (Object)null)
				{
					val.anchoredPosition = anchoredPosition;
				}
			}
		}

		public static void ResetReticlePosition()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			if (reticleParentFound && (Object)(object)reticleParentTransform != (Object)null)
			{
				reticleParentTransform.anchoredPosition = Vector2.zero;
			}
			if (!interactElementsFound)
			{
				return;
			}
			RectTransform[] array = interactTransforms;
			foreach (RectTransform val in array)
			{
				if ((Object)(object)val != (Object)null)
				{
					val.anchoredPosition = Vector2.zero;
				}
			}
		}

		internal static void InvalidateCache()
		{
			if (reticleParentFound && (Object)(object)reticleParentTransform == (Object)null)
			{
				reticleParentFound = false;
				cachedReticleCanvas = null;
				cachedCanvasScaleFactor = 1f;
			}
			if (!interactElementsFound)
			{
				return;
			}
			bool flag = false;
			RectTransform[] array = interactTransforms;
			for (int i = 0; i < array.Length; i++)
			{
				if ((Object)(object)array[i] == (Object)null)
				{
					flag = true;
					break;
				}
			}
			if (flag)
			{
				interactElementsFound = false;
				interactElementsSearched = false;
				interactTransforms = null;
			}
		}
	}
	internal static class TrackingConstants
	{
		internal const float MovementThreshold = 0.1f;
	}
}
namespace PeakHeadTracking.Input
{
	public class HotkeyManager : MonoBehaviour
	{
		private ModConfiguration config;

		private CameraController cameraController;

		private OpenTrackReceiver coreReceiver;

		private bool wasTogglePressed;

		private bool wasRecenterPressed;

		private bool wasReloadPressed;

		private bool wasPositionTogglePressed;

		public void Initialize(ModConfiguration modConfig, CameraController camController, OpenTrackReceiver trackReceiver)
		{
			config = modConfig;
			cameraController = camController;
			coreReceiver = trackReceiver;
			PeakHeadTrackingPlugin.Logger.LogDebug((object)"HotkeyManager initialized");
		}

		private void Update()
		{
			if (config != null)
			{
				HandleToggleTracking();
				HandleRecenterView();
				HandleReloadConfig();
				HandleTogglePosition();
			}
		}

		private void HandleToggleTracking()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			bool key = Input.GetKey(config.ToggleTrackingKey.Value);
			if (key && !wasTogglePressed)
			{
				bool flag = !config.TrackingEnabled.Value;
				config.TrackingEnabled.Value = flag;
				if (flag && !coreReceiver.IsReceiving && !coreReceiver.IsFailed)
				{
					coreReceiver.Start(config.UdpPort.Value);
				}
				cameraController.SetTrackingEnabled(flag);
				PeakHeadTrackingPlugin.Logger.LogInfo((object)("Tracking toggled: " + (flag ? "ON" : "OFF")));
			}
			wasTogglePressed = key;
		}

		private void HandleRecenterView()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			bool key = Input.GetKey(config.RecenterKey.Value);
			if (key && !wasRecenterPressed)
			{
				cameraController.RecenterView();
				PeakHeadTrackingPlugin.Logger.LogInfo((object)"View recentered");
			}
			wasRecenterPressed = key;
		}

		private void HandleReloadConfig()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			bool key = Input.GetKey(config.ReloadConfigKey.Value);
			if (key && !wasReloadPressed)
			{
				config.Reload();
				coreReceiver.Dispose();
				coreReceiver.Start(config.UdpPort.Value);
				PeakHeadTrackingPlugin.Logger.LogInfo((object)"Configuration reloaded");
			}
			wasReloadPressed = key;
		}

		private void HandleTogglePosition()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			bool key = Input.GetKey(config.TogglePositionKey.Value);
			if (key && !wasPositionTogglePressed)
			{
				config.PositionEnabled.Value = !config.PositionEnabled.Value;
				PeakHeadTrackingPlugin.Logger.LogInfo((object)("Position tracking " + (config.PositionEnabled.Value ? "enabled" : "disabled")));
			}
			wasPositionTogglePressed = key;
		}

		public void ResetStates()
		{
			wasTogglePressed = false;
			wasRecenterPressed = false;
			wasReloadPressed = false;
			wasPositionTogglePressed = false;
		}

		private void OnDisable()
		{
			ResetStates();
		}
	}
}
namespace PeakHeadTracking.Config
{
	public static class ConfigCategories
	{
		public const string CONNECTION = "01. Connection";

		public const string GENERAL = "02. General";

		public const string SENSITIVITY = "03. Sensitivity";

		public const string LIMITS = "04. Rotation Limits";

		public const string SMOOTHING = "05. Smoothing";

		public const string DEADZONE = "06. Deadzone";

		public const string HOTKEYS = "07. Hotkeys";

		public const string ADVANCED = "08. Advanced";
	}
	public class ConfigChangedEventArgs : EventArgs
	{
		public string SettingName { get; set; }

		public object OldValue { get; set; }

		public object NewValue { get; set; }

		public string Category { get; set; }
	}
	public class ConfigProfile
	{
		public string Name { get; set; }

		public string Description { get; set; }

		public DateTime CreatedDate { get; set; }

		public DateTime ModifiedDate { get; set; }

		public string GameName { get; set; }

		public Dictionary<string, object> Settings { get; set; } = new Dictionary<string, object>();


		public bool IsDefault { get; set; }

		public bool IsReadOnly { get; set; }

		public void ExportFromConfig(ModConfiguration config)
		{
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			Settings.Clear();
			Settings["UdpPort"] = config.UdpPort.Value;
			Settings["ReconnectTimeout"] = config.ReconnectTimeout.Value;
			Settings["PacketBufferSize"] = config.PacketBufferSize.Value;
			Settings["TrackingEnabled"] = config.TrackingEnabled.Value;
			Settings["EnableAudioFeedback"] = config.EnableAudioFeedback.Value;
			Settings["YawSensitivity"] = config.YawSensitivity.Value;
			Settings["PitchSensitivity"] = config.PitchSensitivity.Value;
			Settings["RollSensitivity"] = config.RollSensitivity.Value;
			Settings["InvertYaw"] = config.InvertYaw.Value;
			Settings["InvertPitch"] = config.InvertPitch.Value;
			Settings["InvertRoll"] = config.InvertRoll.Value;
			Settings["EnableRoll"] = config.EnableRoll.Value;
			Settings["Smoothing"] = config.Smoothing.Value;
			Settings["EnableDeadzone"] = config.EnableDeadzone.Value;
			Settings["DeadzoneYaw"] = config.DeadzoneYaw.Value;
			Settings["DeadzonePitch"] = config.DeadzonePitch.Value;
			Settings["DeadzoneRoll"] = config.DeadzoneRoll.Value;
			Settings["ToggleTrackingKey"] = config.ToggleTrackingKey.Value;
			Settings["RecenterKey"] = config.RecenterKey.Value;
			Settings["ReloadConfigKey"] = config.ReloadConfigKey.Value;
			Settings["DebugLogging"] = config.DebugLogging.Value;
			Settings["UpdateRate"] = config.UpdateRate.Value;
			ModifiedDate = DateTime.Now;
		}

		public void ImportToConfig(ModConfiguration config)
		{
			//IL_029e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
			if (Settings.TryGetValue("UdpPort", out var value))
			{
				config.UdpPort.Value = Convert.ToInt32(value);
			}
			if (Settings.TryGetValue("ReconnectTimeout", out var value2))
			{
				config.ReconnectTimeout.Value = Convert.ToInt32(value2);
			}
			if (Settings.TryGetValue("PacketBufferSize", out var value3))
			{
				config.PacketBufferSize.Value = Convert.ToInt32(value3);
			}
			if (Settings.TryGetValue("TrackingEnabled", out var value4))
			{
				config.TrackingEnabled.Value = Convert.ToBoolean(value4);
			}
			if (Settings.TryGetValue("EnableAudioFeedback", out var value5))
			{
				config.EnableAudioFeedback.Value = Convert.ToBoolean(value5);
			}
			if (Settings.TryGetValue("YawSensitivity", out var value6))
			{
				config.YawSensitivity.Value = Convert.ToSingle(value6);
			}
			if (Settings.TryGetValue("PitchSensitivity", out var value7))
			{
				config.PitchSensitivity.Value = Convert.ToSingle(value7);
			}
			if (Settings.TryGetValue("RollSensitivity", out var value8))
			{
				config.RollSensitivity.Value = Convert.ToSingle(value8);
			}
			if (Settings.TryGetValue("InvertYaw", out var value9))
			{
				config.InvertYaw.Value = Convert.ToBoolean(value9);
			}
			if (Settings.TryGetValue("InvertPitch", out var value10))
			{
				config.InvertPitch.Value = Convert.ToBoolean(value10);
			}
			if (Settings.TryGetValue("InvertRoll", out var value11))
			{
				config.InvertRoll.Value = Convert.ToBoolean(value11);
			}
			if (Settings.TryGetValue("EnableRoll", out var value12))
			{
				config.EnableRoll.Value = Convert.ToBoolean(value12);
			}
			if (Settings.TryGetValue("Smoothing", out var value13))
			{
				config.Smoothing.Value = Convert.ToSingle(value13);
			}
			if (Settings.TryGetValue("EnableDeadzone", out var value14))
			{
				config.EnableDeadzone.Value = Convert.ToBoolean(value14);
			}
			if (Settings.TryGetValue("DeadzoneYaw", out var value15))
			{
				config.DeadzoneYaw.Value = Convert.ToSingle(value15);
			}
			if (Settings.TryGetValue("DeadzonePitch", out var value16))
			{
				config.DeadzonePitch.Value = Convert.ToSingle(value16);
			}
			if (Settings.TryGetValue("DeadzoneRoll", out var value17))
			{
				config.DeadzoneRoll.Value = Convert.ToSingle(value17);
			}
			if (Settings.TryGetValue("ToggleTrackingKey", out var value18))
			{
				config.ToggleTrackingKey.Value = (KeyCode)value18;
			}
			if (Settings.TryGetValue("RecenterKey", out var value19))
			{
				config.RecenterKey.Value = (KeyCode)value19;
			}
			if (Settings.TryGetValue("ReloadConfigKey", out var value20))
			{
				config.ReloadConfigKey.Value = (KeyCode)value20;
			}
			if (Settings.TryGetValue("DebugLogging", out var value21))
			{
				config.DebugLogging.Value = Convert.ToBoolean(value21);
			}
			if (Settings.TryGetValue("UpdateRate", out var value22))
			{
				config.UpdateRate.Value = Convert.ToInt32(value22);
			}
		}

		public ConfigProfile Clone(string newName)
		{
			return new ConfigProfile
			{
				Name = newName,
				Description = Description + " (Copy)",
				CreatedDate = DateTime.Now,
				ModifiedDate = DateTime.Now,
				GameName = GameName,
				IsDefault = false,
				IsReadOnly = false,
				Settings = new Dictionary<string, object>(Settings)
			};
		}
	}
	public class ConfigurationManager
	{
		private static ConfigurationManager instance;

		private ModConfiguration modConfig;

		private ProfileManager profileManager;

		private bool isInitialized;

		private readonly Dictionary<string, List<Action>> settingCallbacks = new Dictionary<string, List<Action>>();

		public static ConfigurationManager Instance => instance ?? (instance = new ConfigurationManager());

		public ModConfiguration Config => modConfig;

		public ProfileManager Profiles => profileManager;

		public event EventHandler<ConfigChangedEventArgs> ConfigChanged;

		public event EventHandler<string> ProfileChanged;

		public void Initialize(ConfigFile config)
		{
			if (!isInitialized)
			{
				modConfig = new ModConfiguration();
				modConfig.Initialize(config);
				profileManager = new ProfileManager(config);
				if (profileManager.GetActiveProfile() != null)
				{
					profileManager.ApplyProfileToConfig(modConfig);
				}
				SetupConfigurationWatchers();
				isInitialized = true;
				PeakHeadTrackingPlugin.Logger.LogInfo((object)"Configuration manager initialized");
			}
		}

		private void SetupConfigurationWatchers()
		{
			modConfig.YawSensitivity.SettingChanged += delegate
			{
				OnConfigChanged("YawSensitivity", modConfig.YawSensitivity.Value, "03. Sensitivity");
			};
			modConfig.PitchSensitivity.SettingChanged += delegate
			{
				OnConfigChanged("PitchSensitivity", modConfig.PitchSensitivity.Value, "03. Sensitivity");
			};
			modConfig.RollSensitivity.SettingChanged += delegate
			{
				OnConfigChanged("RollSensitivity", modConfig.RollSensitivity.Value, "03. Sensitivity");
			};
			modConfig.InvertYaw.SettingChanged += delegate
			{
				OnConfigChanged("InvertYaw", modConfig.InvertYaw.Value, "03. Sensitivity");
			};
			modConfig.InvertPitch.SettingChanged += delegate
			{
				OnConfigChanged("InvertPitch", modConfig.InvertPitch.Value, "03. Sensitivity");
			};
			modConfig.InvertRoll.SettingChanged += delegate
			{
				OnConfigChanged("InvertRoll", modConfig.InvertRoll.Value, "03. Sensitivity");
			};
			modConfig.EnableDeadzone.SettingChanged += delegate
			{
				OnConfigChanged("EnableDeadzone", modConfig.EnableDeadzone.Value, "06. Deadzone");
			};
			modConfig.DeadzoneYaw.SettingChanged += delegate
			{
				OnConfigChanged("DeadzoneYaw", modConfig.DeadzoneYaw.Value, "06. Deadzone");
			};
			modConfig.DeadzonePitch.SettingChanged += delegate
			{
				OnConfigChanged("DeadzonePitch", modConfig.DeadzonePitch.Value, "06. Deadzone");
			};
			modConfig.DeadzoneRoll.SettingChanged += delegate
			{
				OnConfigChanged("DeadzoneRoll", modConfig.DeadzoneRoll.Value, "06. Deadzone");
			};
			modConfig.EnablePitchLimits.SettingChanged += delegate
			{
				OnConfigChanged("EnablePitchLimits", modConfig.EnablePitchLimits.Value, "04. Rotation Limits");
			};
			modConfig.MinPitch.SettingChanged += delegate
			{
				OnConfigChanged("MinPitch", modConfig.MinPitch.Value, "04. Rotation Limits");
			};
			modConfig.MaxPitch.SettingChanged += delegate
			{
				OnConfigChanged("MaxPitch", modConfig.MaxPitch.Value, "04. Rotation Limits");
			};
			modConfig.EnableRoll.SettingChanged += delegate
			{
				OnConfigChanged("EnableRoll", modConfig.EnableRoll.Value, "04. Rotation Limits");
			};
			modConfig.EnableRollLimits.SettingChanged += delegate
			{
				OnConfigChanged("EnableRollLimits", modConfig.EnableRollLimits.Value, "04. Rotation Limits");
			};
			modConfig.MaxRoll.SettingChanged += delegate
			{
				OnConfigChanged("MaxRoll", modConfig.MaxRoll.Value, "04. Rotation Limits");
			};
		}

		private void OnConfigChanged(string settingName, object newValue, string category)
		{
			this.ConfigChanged?.Invoke(this, new ConfigChangedEventArgs
			{
				SettingName = settingName,
				NewValue = newValue,
				Category = category
			});
			if (!settingCallbacks.TryGetValue(settingName, out var value))
			{
				return;
			}
			foreach (Action item in value)
			{
				item?.Invoke();
			}
		}

		public void RegisterSettingChangeCallback(string settingName, Action callback)
		{
			if (!settingCallbacks.ContainsKey(settingName))
			{
				settingCallbacks[settingName] = new List<Action>();
			}
			settingCallbacks[settingName].Add(callback);
		}

		public void UnregisterSettingChangeCallback(string settingName, Action callback)
		{
			if (settingCallbacks.TryGetValue(settingName, out var value))
			{
				value.Remove(callback);
			}
		}

		public void ReloadConfiguration()
		{
			modConfig?.Reload();
			if (profileManager?.GetActiveProfile() != null)
			{
				profileManager.ApplyProfileToConfig(modConfig);
			}
			PeakHeadTrackingPlugin.Logger.LogInfo((object)"Configuration reloaded");
		}

		public void SaveConfiguration()
		{
			modConfig?.Save();
			profileManager?.SaveCurrentToProfile(modConfig);
			PeakHeadTrackingPlugin.Logger.LogInfo((object)"Configuration saved");
		}

		public void SwitchProfile(string profileName)
		{
			profileManager.LoadProfile(profileName);
			profileManager.ApplyProfileToConfig(modConfig);
			this.ProfileChanged?.Invoke(this, profileName);
			PeakHeadTrackingPlugin.Logger.LogInfo((object)("Switched to profile: " + profileName));
		}

		public void ResetToDefaults()
		{
			modConfig.YawSensitivity.Value = (float)((ConfigEntryBase)modConfig.YawSensitivity).DefaultValue;
			modConfig.PitchSensitivity.Value = (float)((ConfigEntryBase)modConfig.PitchSensitivity).DefaultValue;
			modConfig.RollSensitivity.Value = (float)((ConfigEntryBase)modConfig.RollSensitivity).DefaultValue;
			modConfig.InvertYaw.Value = (bool)((ConfigEntryBase)modConfig.InvertYaw).DefaultValue;
			modConfig.InvertPitch.Value = (bool)((ConfigEntryBase)modConfig.InvertPitch).DefaultValue;
			modConfig.InvertRoll.Value = (bool)((ConfigEntryBase)modConfig.InvertRoll).DefaultValue;
			SaveConfiguration();
		}

		public void ExportConfiguration(string filePath)
		{
			using (StreamWriter streamWriter = new StreamWriter(filePath))
			{
				streamWriter.WriteLine("# PeakHeadTracking Configuration Export");
				streamWriter.WriteLine($"# Exported: {DateTime.Now}");
				streamWriter.WriteLine("# Profile: " + profileManager.GetActiveProfileName());
				streamWriter.WriteLine();
				streamWriter.WriteLine($"UdpPort={modConfig.UdpPort.Value}");
				streamWriter.WriteLine($"TrackingEnabled={modConfig.TrackingEnabled.Value}");
				streamWriter.WriteLine($"YawSensitivity={modConfig.YawSensitivity.Value}");
				streamWriter.WriteLine($"PitchSensitivity={modConfig.PitchSensitivity.Value}");
				streamWriter.WriteLine($"RollSensitivity={modConfig.RollSensitivity.Value}");
				streamWriter.WriteLine($"InvertYaw={modConfig.InvertYaw.Value}");
				streamWriter.WriteLine($"InvertPitch={modConfig.InvertPitch.Value}");
				streamWriter.WriteLine($"InvertRoll={modConfig.InvertRoll.Value}");
			}
			PeakHeadTrackingPlugin.Logger.LogInfo((object)("Configuration exported to " + filePath));
		}

		public void Cleanup()
		{
			settingCallbacks.Clear();
			this.ConfigChanged = null;
			this.ProfileChanged = null;
			isInitialized = false;
		}
	}
	public class ModConfiguration
	{
		private ConfigFile configFile;

		public ConfigEntry<int> UdpPort { get; private set; }

		public ConfigEntry<int> ReconnectTimeout { get; private set; }

		public ConfigEntry<int> PacketBufferSize { get; private set; }

		public ConfigEntry<bool> TrackingEnabled { get; private set; }

		public ConfigEntry<bool> EnableAudioFeedback { get; private set; }

		public ConfigEntry<float> YawSensitivity { get; private set; }

		public ConfigEntry<float> PitchSensitivity { get; private set; }

		public ConfigEntry<float> RollSensitivity { get; private set; }

		public ConfigEntry<bool> InvertYaw { get; private set; }

		public ConfigEntry<bool> InvertPitch { get; private set; }

		public ConfigEntry<bool> InvertRoll { get; private set; }

		public ConfigEntry<bool> EnablePitchLimits { get; private set; }

		public ConfigEntry<float> MinPitch { get; private set; }

		public ConfigEntry<float> MaxPitch { get; private set; }

		public ConfigEntry<bool> EnableRoll { get; private set; }

		public ConfigEntry<bool> EnableRollLimits { get; private set; }

		public ConfigEntry<float> MaxRoll { get; private set; }

		public ConfigEntry<float> Smoothing { get; private set; }

		public ConfigEntry<bool> EnableDeadzone { get; private set; }

		public ConfigEntry<float> DeadzoneYaw { get; private set; }

		public ConfigEntry<float> DeadzonePitch { get; private set; }

		public ConfigEntry<float> DeadzoneRoll { get; private set; }

		public ConfigEntry<KeyCode> ToggleTrackingKey { get; private set; }

		public ConfigEntry<KeyCode> RecenterKey { get; private set; }

		public ConfigEntry<KeyCode> ReloadConfigKey { get; private set; }

		public ConfigEntry<KeyCode> TogglePositionKey { get; private set; }

		public ConfigEntry<KeyCode> ToggleReticleKey { get; private set; }

		public ConfigEntry<bool> ShowReticle { get; private set; }

		public ConfigEntry<bool> DebugLogging { get; private set; }

		public ConfigEntry<int> UpdateRate { get; private set; }

		public ConfigEntry<bool> MaintainRelativePosition { get; private set; }

		public ConfigEntry<bool> PositionEnabled { get; private set; }

		public ConfigEntry<float> PositionSensitivityX { get; private set; }

		public ConfigEntry<float> PositionSensitivityY { get; private set; }

		public ConfigEntry<float> PositionSensitivityZ { get; private set; }

		public ConfigEntry<float> PositionLimitX { get; private set; }

		public ConfigEntry<float> PositionLimitY { get; private set; }

		public ConfigEntry<float> PositionLimitZ { get; private set; }

		public ConfigEntry<float> PositionSmoothing { get; private set; }

		public ConfigEntry<float> NearClipOverride { get; private set; }

		public void Initialize(ConfigFile config)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Expected O, but got Unknown
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Expected O, but got Unknown
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Expected O, but got Unknown
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Expected O, but got Unknown
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Expected O, but got Unknown
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Expected O, but got Unknown
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d2: Expected O, but got Unknown
			//IL_0301: Unknown result type (might be due to invalid IL or missing references)
			//IL_030b: Expected O, but got Unknown
			//IL_0356: Unknown result type (might be due to invalid IL or missing references)
			//IL_0360: Expected O, but got Unknown
			//IL_038f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0399: Expected O, but got Unknown
			//IL_03c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d2: Expected O, but got Unknown
			//IL_04d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04da: Expected O, but got Unknown
			//IL_0541: Unknown result type (might be due to invalid IL or missing references)
			//IL_054b: Expected O, but got Unknown
			//IL_057a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0584: Expected O, but got Unknown
			//IL_05b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_05bd: Expected O, but got Unknown
			//IL_05ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f6: Expected O, but got Unknown
			//IL_0625: Unknown result type (might be due to invalid IL or missing references)
			//IL_062f: Expected O, but got Unknown
			//IL_065e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0668: Expected O, but got Unknown
			//IL_0697: Unknown result type (might be due to invalid IL or missing references)
			//IL_06a1: Expected O, but got Unknown
			//IL_06d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_06da: Expected O, but got Unknown
			configFile = config;
			UdpPort = config.Bind<int>("01. Connection", "UDP Port", 4242, new ConfigDescription("Port number for OpenTrack UDP connection", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1024, 65535), Array.Empty<object>()));
			ReconnectTimeout = config.Bind<int>("01. Connection", "Reconnect Timeout", 5, new ConfigDescription("Seconds to wait before attempting reconnection", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 60), Array.Empty<object>()));
			PacketBufferSize = config.Bind<int>("01. Connection", "Packet Buffer Size", 100, new ConfigDescription("Maximum number of packets to buffer", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 500), Array.Empty<object>()));
			TrackingEnabled = config.Bind<bool>("02. General", "Tracking Enabled", true, "Enable head tracking on startup");
			EnableAudioFeedback = config.Bind<bool>("02. General", "Enable Audio Feedback", true, "Play sounds for tracking state changes");
			YawSensitivity = config.Bind<float>("03. Sensitivity", "Yaw Sensitivity", 1f, new ConfigDescription("Yaw (left/right) rotation multiplier", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>()));
			PitchSensitivity = config.Bind<float>("03. Sensitivity", "Pitch Sensitivity", 1f, new ConfigDescription("Pitch (up/down) rotation multiplier", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>()));
			RollSensitivity = config.Bind<float>("03. Sensitivity", "Roll Sensitivity", 1f, new ConfigDescription("Roll (tilt) rotation multiplier", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>()));
			InvertYaw = config.Bind<bool>("03. Sensitivity", "Invert Yaw", false, "Invert yaw (left/right) axis");
			InvertPitch = config.Bind<bool>("03. Sensitivity", "Invert Pitch", false, "Invert pitch (up/down) axis");
			InvertRoll = config.Bind<bool>("03. Sensitivity", "Invert Roll", false, "Invert roll (tilt) axis");
			EnablePitchLimits = config.Bind<bool>("04. Rotation Limits", "Enable Pitch Limits", true, "Limit pitch rotation range");
			MinPitch = config.Bind<float>("04. Rotation Limits", "Minimum Pitch", -85f, new ConfigDescription("Minimum pitch angle (looking down)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-90f, 0f), Array.Empty<object>()));
			MaxPitch = config.Bind<float>("04. Rotation Limits", "Maximum Pitch", 85f, new ConfigDescription("Maximum pitch angle (looking up)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 90f), Array.Empty<object>()));
			EnableRoll = config.Bind<bool>("04. Rotation Limits", "Enable Roll", true, "Enable roll (head tilt) rotation");
			EnableRollLimits = config.Bind<bool>("04. Rotation Limits", "Enable Roll Limits", true, "Limit roll rotation range");
			MaxRoll = config.Bind<float>("04. Rotation Limits", "Maximum Roll", 30f, new ConfigDescription("Maximum roll angle in either direction", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 90f), Array.Empty<object>()));
			Smoothing = config.Bind<float>("05. Smoothing", "Smoothing", 0f, new ConfigDescription("Smoothing factor (higher = smoother but adds latency). Remote connections automatically use a minimum of 0.15 for network latency compensation.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			EnableDeadzone = config.Bind<bool>("06. Deadzone", "Enable Deadzone", false, "Ignore small movements near center");
			DeadzoneYaw = config.Bind<float>("06. Deadzone", "Yaw Deadzone", 0f, new ConfigDescription("Deadzone for yaw axis (degrees)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
			DeadzonePitch = config.Bind<float>("06. Deadzone", "Pitch Deadzone", 0f, new ConfigDescription("Deadzone for pitch axis (degrees)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
			DeadzoneRoll = config.Bind<float>("06. Deadzone", "Roll Deadzone", 0f, new ConfigDescription("Deadzone for roll axis (degrees)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
			ToggleTrackingKey = config.Bind<KeyCode>("07. Hotkeys", "Toggle Tracking", (KeyCode)279, "Key to enable/disable tracking");
			RecenterKey = config.Bind<KeyCode>("07. Hotkeys", "Recenter View", (KeyCode)278, "Key to recenter the view");
			ReloadConfigKey = config.Bind<KeyCode>("07. Hotkeys", "Reload Config", (KeyCode)293, "Key to reload configuration");
			TogglePositionKey = config.Bind<KeyCode>("07. Hotkeys", "Toggle Position", (KeyCode)280, "Key to toggle positional tracking on/off");
			ToggleReticleKey = config.Bind<KeyCode>("07. Hotkeys", "Toggle Reticle", (KeyCode)277, "Key to toggle reticle compensation on/off");
			ShowReticle = config.Bind<bool>("02. General", "Show Reticle", true, "Show reticle compensation (moves crosshair to show aim point during head tracking)");
			DebugLogging = config.Bind<bool>("08. Advanced", "Debug Logging", false, "Enable detailed debug logging");
			UpdateRate = config.Bind<int>("08. Advanced", "Update Rate", 60, new ConfigDescription("Target update rate in Hz", (AcceptableValueBase)(object)new AcceptableValueRange<int>(30, 120), Array.Empty<object>()));
			MaintainRelativePosition = config.Bind<bool>("08. Advanced", "Maintain Relative Position", true, "Maintain camera position relative to target");
			PositionEnabled = config.Bind<bool>("02. General", "Position Enabled", true, "Enable positional tracking (lean in/out/side-to-side)");
			PositionSensitivityX = config.Bind<float>("03. Sensitivity", "Position Sensitivity X", 2f, new ConfigDescription("Multiplier for lateral (left/right) position", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>()));
			PositionSensitivityY = config.Bind<float>("03. Sensitivity", "Position Sensitivity Y", 2f, new ConfigDescription("Multiplier for vertical (up/down) position", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>()));
			PositionSensitivityZ = config.Bind<float>("03. Sensitivity", "Position Sensitivity Z", 2f, new ConfigDescription("Multiplier for depth (forward/back) position", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>()));
			PositionLimitX = config.Bind<float>("03. Sensitivity", "Position Limit X", 0.3f, new ConfigDescription("Maximum lateral displacement in meters", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 0.5f), Array.Empty<object>()));
			PositionLimitY = config.Bind<float>("03. Sensitivity", "Position Limit Y", 0.2f, new ConfigDescription("Maximum vertical displacement in meters", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 0.5f), Array.Empty<object>()));
			PositionLimitZ = config.Bind<float>("03. Sensitivity", "Position Limit Z", 0.4f, new ConfigDescription("Maximum depth displacement in meters", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 0.5f), Array.Empty<object>()));
			PositionSmoothing = config.Bind<float>("05. Smoothing", "Position Smoothing", 0.15f, new ConfigDescription("Smoothing for positional tracking (0 = instant, 1 = very slow)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			NearClipOverride = config.Bind<float>("08. Advanced", "Near Clip Override", 0.15f, new ConfigDescription("Minimum near clip plane distance in meters. Prevents seeing through the character model during head bobbing.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 0.5f), Array.Empty<object>()));
		}

		public void Reload()
		{
			ConfigFile obj = configFile;
			if (obj != null)
			{
				obj.Reload();
			}
		}

		public void Save()
		{
			ConfigFile obj = configFile;
			if (obj != null)
			{
				obj.Save();
			}
		}
	}
	public class ProfileManager
	{
		private readonly string profilesDirectory;

		private readonly ConfigFile mainConfig;

		private readonly Dictionary<string, ConfigProfile> profiles = new Dictionary<string, ConfigProfile>();

		private ConfigProfile activeProfile;

		private string activeProfileName;

		private List<string> cachedProfileNames;

		public ProfileManager(ConfigFile config)
		{
			mainConfig = config;
			profilesDirectory = Path.Combine(Paths.ConfigPath, "PeakHeadTracking", "Profiles");
			if (!Directory.Exists(profilesDirectory))
			{
				Directory.CreateDirectory(profilesDirectory);
			}
			LoadProfiles();
			if (profiles.Count == 0)
			{
				CreateDefaultProfiles();
			}
			string value = mainConfig.Bind<string>("Profile", "LastActiveProfile", "Default", "Last active profile name").Value;
			if (profiles.ContainsKey(value))
			{
				LoadProfile(value);
			}
			else
			{
				LoadProfile("Default");
			}
		}

		private void CreateDefaultProfiles()
		{
			ConfigProfile configProfile = new ConfigProfile
			{
				Name = "Default",
				Description = "Default configuration for most games",
				CreatedDate = DateTime.Now,
				ModifiedDate = DateTime.Now,
				GameName = "General",
				IsDefault = true,
				IsReadOnly = false
			};
			configProfile.Settings["YawSensitivity"] = 1f;
			configProfile.Settings["PitchSensitivity"] = 1f;
			configProfile.Settings["RollSensitivity"] = 1f;
			configProfile.Settings["Smoothing"] = 0f;
			profiles["Default"] = configProfile;
			SaveProfile(configProfile);
			ConfigProfile configProfile2 = new ConfigProfile
			{
				Name = "FPS_Competitive",
				Description = "Optimized for competitive FPS games",
				CreatedDate = DateTime.Now,
				ModifiedDate = DateTime.Now,
				GameName = "FPS",
				IsDefault = false,
				IsReadOnly = false
			};
			configProfile2.Settings["YawSensitivity"] = 0.8f;
			configProfile2.Settings["PitchSensitivity"] = 0.8f;
			configProfile2.Settings["RollSensitivity"] = 0.5f;
			configProfile2.Settings["Smoothing"] = 0f;
			profiles["FPS_Competitive"] = configProfile2;
			SaveProfile(configProfile2);
			ConfigProfile configProfile3 = new ConfigProfile
			{
				Name = "Simulation",
				Description = "Realistic head movement for simulation games",
				CreatedDate = DateTime.Now,
				ModifiedDate = DateTime.Now,
				GameName = "Simulation",
				IsDefault = false,
				IsReadOnly = false
			};
			configProfile3.Settings["YawSensitivity"] = 1.2f;
			configProfile3.Settings["PitchSensitivity"] = 1.2f;
			configProfile3.Settings["RollSensitivity"] = 1f;
			configProfile3.Settings["Smoothing"] = 0.1f;
			profiles["Simulation"] = configProfile3;
			SaveProfile(configProfile3);
		}

		private void LoadProfiles()
		{
			profiles.Clear();
			string[] files = Directory.GetFiles(profilesDirectory, "*.profile");
			foreach (string text in files)
			{
				string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text);
				ConfigProfile configProfile = LoadProfileFromFile(text);
				if (configProfile != null)
				{
					profiles[fileNameWithoutExtension] = configProfile;
				}
			}
		}

		private ConfigProfile LoadProfileFromFile(string filePath)
		{
			string[] array = File.ReadAllLines(filePath);
			ConfigProfile configProfile = new ConfigProfile();
			string[] array2 = array;
			foreach (string text in array2)
			{
				if (string.IsNullOrWhiteSpace(text) || text.StartsWith("#"))
				{
					continue;
				}
				string[] array3 = text.Split(new char[1] { '=' });
				if (array3.Length != 2)
				{
					continue;
				}
				string text2 = array3[0].Trim();
				string text3 = array3[1].Trim();
				switch (text2)
				{
				case "Name":
					configProfile.Name = text3;
					continue;
				case "Description":
					configProfile.Description = text3;
					continue;
				case "GameName":
					configProfile.GameName = text3;
					continue;
				case "CreatedDate":
					configProfile.CreatedDate = DateTime.Parse(text3);
					continue;
				case "ModifiedDate":
					configProfile.ModifiedDate = DateTime.Parse(text3);
					continue;
				case "IsDefault":
					configProfile.IsDefault = bool.Parse(text3);
					continue;
				case "IsReadOnly":
					configProfile.IsReadOnly = bool.Parse(text3);
					continue;
				}
				if (text2.StartsWith("Setting."))
				{
					string key = text2.Substring(8);
					configProfile.Settings[key] = ParseValue(text3);
				}
			}
			return configProfile;
		}

		private object ParseValue(string value)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			if (bool.TryParse(value, out var result))
			{
				return result;
			}
			if (int.TryParse(value, out var result2))
			{
				return result2;
			}
			if (float.TryParse(value, out var result3))
			{
				return result3;
			}
			if (Enum.TryParse<KeyCode>(value, out KeyCode result4))
			{
				return result4;
			}
			return value;
		}

		public void SaveProfile(ConfigProfile profile)
		{
			if (profile.IsReadOnly)
			{
				throw new InvalidOperationException("Cannot save read-only profile: " + profile.Name);
			}
			using StreamWriter streamWriter = new StreamWriter(Path.Combine(profilesDirectory, profile.Name + ".profile"));
			streamWriter.WriteLine("# PeakHeadTracking Configuration Profile");
			streamWriter.WriteLine($"# Generated: {DateTime.Now}");
			streamWriter.WriteLine();
			streamWriter.WriteLine("Name=" + profile.Name);
			streamWriter.WriteLine("Description=" + profile.Description);
			streamWriter.WriteLine("GameName=" + profile.GameName);
			streamWriter.WriteLine($"CreatedDate={profile.CreatedDate:yyyy-MM-dd HH:mm:ss}");
			streamWriter.WriteLine($"ModifiedDate={profile.ModifiedDate:yyyy-MM-dd HH:mm:ss}");
			streamWriter.WriteLine($"IsDefault={profile.IsDefault}");
			streamWriter.WriteLine($"IsReadOnly={profile.IsReadOnly}");
			streamWriter.WriteLine();
			streamWriter.WriteLine("# Configuration Settings");
			foreach (KeyValuePair<string, object> setting in profile.Settings)
			{
				streamWriter.WriteLine($"Setting.{setting.Key}={setting.Value}");
			}
		}

		public void LoadProfile(string profileName)
		{
			if (!profiles.ContainsKey(profileName))
			{
				throw new KeyNotFoundException("Profile not found: " + profileName);
			}
			activeProfile = profiles[profileName];
			activeProfileName = profileName;
			mainConfig.Bind<string>("Profile", "LastActiveProfile", "Default", (ConfigDescription)null).Value = profileName;
			mainConfig.Save();
			PeakHeadTrackingPlugin.Logger.LogInfo((object)("Loaded profile: " + profileName));
		}

		public ConfigProfile CreateProfile(string name, string description, string gameName = "General")
		{
			if (profiles.ContainsKey(name))
			{
				throw new InvalidOperationException("Profile already exists: " + name);
			}
			ConfigProfile configProfile = new ConfigProfile
			{
				Name = name,
				Description = description,
				CreatedDate = DateTime.Now,
				ModifiedDate = DateTime.Now,
				GameName = gameName,
				IsDefault = false,
				IsReadOnly = false
			};
			profiles[name] = configProfile;
			cachedProfileNames = null;
			SaveProfile(configProfile);
			return configProfile;
		}

		public void DeleteProfile(string profileName)
		{
			if (!profiles.ContainsKey(profileName))
			{
				throw new KeyNotFoundException("Profile not found: " + profileName);
			}
			ConfigProfile configProfile = profiles[profileName];
			if (configProfile.IsReadOnly || configProfile.IsDefault)
			{
				throw new InvalidOperationException("Cannot delete protected profile: " + profileName);
			}
			profiles.Remove(profileName);
			cachedProfileNames = null;
			string path = Path.Combine(profilesDirectory, profileName + ".profile");
			if (File.Exists(path))
			{
				File.Delete(path);
			}
			if (activeProfileName == profileName)
			{
				LoadProfile("Default");
			}
		}

		public ConfigProfile DuplicateProfile(string sourceName, string newName)
		{
			if (!profiles.ContainsKey(sourceName))
			{
				throw new KeyNotFoundException("Source profile not found: " + sourceName);
			}
			if (profiles.ContainsKey(newName))
			{
				throw new InvalidOperationException("Profile already exists: " + newName);
			}
			ConfigProfile configProfile = profiles[sourceName].Clone(newName);
			configProfile.IsReadOnly = false;
			configProfile.IsDefault = false;
			profiles[newName] = configProfile;
			cachedProfileNames = null;
			SaveProfile(configProfile);
			return configProfile;
		}

		public List<string> GetProfileNames()
		{
			if (cachedProfileNames == null)
			{
				cachedProfileNames = profiles.Keys.ToList();
				cachedProfileNames.Sort(StringComparer.Ordinal);
			}
			return cachedProfileNames;
		}

		public ConfigProfile GetActiveProfile()
		{
			return activeProfile;
		}

		public string GetActiveProfileName()
		{
			return activeProfileName;
		}

		public void SaveCurrentToProfile(ModConfiguration config)
		{
			if (activeProfile != null && !activeProfile.IsReadOnly)
			{
				activeProfile.ExportFromConfig(config);
				SaveProfile(activeProfile);
			}
		}

		public void ApplyProfileToConfig(ModConfiguration config)
		{
			if (activeProfile != null)
			{
				activeProfile.ImportToConfig(config);
				config.Save();
			}
		}
	}
}
namespace PeakHeadTracking.Camera
{
	[DefaultExecutionOrder(1000)]
	public class CameraController : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <FindCameraCoroutine>d__16 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public CameraController <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <FindCameraCoroutine>d__16(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_006e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0078: Expected O, but got Unknown
				int num = <>1__state;
				CameraController cameraController = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					break;
				case 1:
					<>1__state = -1;
					break;
				}
				while ((Object)(object)cameraController.mainCamera == (Object)null && cameraController.cameraSearchAttempts < 10)
				{
					cameraController.FindMainCamera();
					if ((Object)(object)cameraController.mainCamera == (Object)null)
					{
						cameraController.cameraSearchAttempts++;
						PeakHeadTrackingPlugin.Logger.LogDebug((object)$"Camera search attempt {cameraController.cameraSearchAttempts}/{10}");
						<>2__current = (object)new WaitForSeconds(1f);
						<>1__state = 1;
						return true;
					}
				}
				if ((Object)(object)cameraController.mainCamera == (Object)null)
				{
					PeakHeadTrackingPlugin.Logger.LogError((object)"Failed to find camera after maximum attempts");
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private ModConfiguration config;

		private OpenTrackReceiver coreReceiver;

		private TrackingProcessor processor;

		private PoseInterpolator interpolator;

		private const int DebugLogIntervalFrames = 120;

		private Camera mainCamera;

		private Transform cameraTransform;

		private const float CAMERA_SEARCH_INTERVAL_SECONDS = 1f;

		private int cameraSearchAttempts;

		private const int MAX_CAMERA_SEARCH_ATTEMPTS = 10;

		private bool isTrackingActive;

		private bool isInitialized;

		private bool wasReceiving;

		public bool IsTrackingActive
		{
			get
			{
				if (isTrackingActive && coreReceiver != null)
				{
					return coreReceiver.IsReceiving;
				}
				return false;
			}
		}

		public void Initialize(ModConfiguration modConfig, OpenTrackReceiver trackReceiver, TrackingProcessor trackingProcessor, PoseInterpolator poseInterpolator)
		{
			config = modConfig;
			coreReceiver = trackReceiver;
			processor = trackingProcessor;
			interpolator = poseInterpolator;
			if (config.MaintainRelativePosition == null)
			{
				throw new InvalidOperationException("MaintainRelativePosition configuration is required");
			}
			isInitialized = true;
			PeakHeadTrackingPlugin.Logger.LogDebug((object)"CameraController initialized");
		}

		private void Start()
		{
			if (!isInitialized)
			{
				PeakHeadTrackingPlugin.Logger.LogWarning((object)"CameraController started without initialization");
				return;
			}
			SceneManager.sceneLoaded += OnSceneLoaded;
			((MonoBehaviour)this).StartCoroutine(FindCameraCoroutine());
		}

		private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
		{
			PeakHeadTrackingPlugin.Logger.LogInfo((object)("Scene loaded: " + ((Scene)(ref scene)).name + " - re-finding camera"));
			mainCamera = null;
			cameraTransform = null;
			cameraSearchAttempts = 0;
			((MonoBehaviour)this).StartCoroutine(FindCameraCoroutine());
		}

		[IteratorStateMachine(typeof(<FindCameraCoroutine>d__16))]
		private IEnumerator FindCameraCoroutine()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <FindCameraCoroutine>d__16(0)
			{
				<>4__this = this
			};
		}

		private void FindMainCamera()
		{
			mainCamera = Camera.main;
			if ((Object)(object)mainCamera == (Object)null)
			{
				GameObject val = GameObject.FindWithTag("MainCamera");
				if ((Object)(object)val != (Object)null)
				{
					mainCamera = val.GetComponent<Camera>();
				}
			}
			if ((Object)(object)mainCamera == (Object)null)
			{
				Camera[] array = Object.FindObjectsByType<Camera>((FindObjectsSortMode)0);
				foreach (Camera val2 in array)
				{
					if (((Behaviour)val2).enabled && ((Component)val2).gameObject.activeInHierarchy)
					{
						mainCamera = val2;
						break;
					}
				}
			}
			if ((Object)(object)mainCamera != (Object)null)
			{
				cameraTransform = ((Component)mainCamera).transform;
				PeakHeadTrackingPlugin.Logger.LogInfo((object)("Attached to camera: " + ((Object)mainCamera).name));
			}
		}

		private void LateUpdate()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: 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)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			if (coreReceiver != null && isTrackingActive)
			{
				bool isReceiving = coreReceiver.IsReceiving;
				if (isReceiving && !wasReceiving)
				{
					RecenterView();
					PeakHeadTrackingPlugin.Logger.LogInfo((object)"Auto-recentered: tracking data connected");
				}
				wasReceiving = isReceiving;
				TrackingPose latestPose = coreReceiver.GetLatestPose();
				TrackingPose val = interpolator.Update(latestPose, Time.deltaTime);
				Quat4 val2 = QuaternionUtils.FromYawPitchRoll(((TrackingPose)(ref val)).Yaw, ((TrackingPose)(ref val)).Pitch, ((TrackingPose)(ref val)).Roll);
				float num = default(float);
				float num2 = default(float);
				float num3 = default(float);
				QuaternionUtils.ToEulerYXZ(processor.CenterManager.ApplyOffsetQuat(val2), ref num, ref num2, ref num3);
				float num4 = num;
				DeadzoneSettings deadzone = processor.Deadzone;
				num = DeadzoneUtils.Apply(num4, ((DeadzoneSettings)(ref deadzone)).Yaw);
				float num5 = num2;
				deadzone = processor.Deadzone;
				num2 = DeadzoneUtils.Apply(num5, ((DeadzoneSettings)(ref deadzone)).Pitch);
				float num6 = num3;
				deadzone = processor.Deadzone;
				num3 = DeadzoneUtils.Apply(num6, ((DeadzoneSettings)(ref deadzone)).Roll);
				TrackingPose val3 = new TrackingPose(num, num2, num3, ((TrackingPose)(ref val)).TimestampTicks);
				TrackingPose val4 = ((TrackingPose)(ref val3)).ApplySensitivity(processor.Sensitivity);
				CameraPatches.SetProcessedRotation(((TrackingPose)(ref val4)).Yaw, ((TrackingPose)(ref val4)).Pitch, ((TrackingPose)(ref val4)).Roll);
			}
			if (config != null && config.DebugLogging.Value && Time.frameCount % 120 == 0)
			{
				LogDebugState();
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private void LogDebugState()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			Vector2 headTrackingInput = CameraPatches.GetHeadTrackingInput();
			ManualLogSource logger = PeakHeadTrackingPlugin.Logger;
			if (logger != null)
			{
				logger.LogDebug((object)$"[CameraController] isTrackingActive={isTrackingActive}, headTracking=({headTrackingInput.x:F1}, {headTrackingInput.y:F1})");
			}
		}

		public void SetTrackingEnabled(bool enabled)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			isTrackingActive = enabled;
			CameraPatches.SetHeadTrackingEnabled(enabled);
			if (!enabled)
			{
				wasReceiving = false;
				CameraPatches.SetHeadTrackingInput(0f, 0f);
				if ((Object)(object)mainCamera != (Object)null)
				{
					ViewMatrixModifier.Reset(mainCamera);
				}
			}
			else
			{
				processor.ResetSmoothing();
				interpolator.Reset();
				TrackingPose latestPose = coreReceiver.GetLatestPose();
				processor.RecenterTo(latestPose);
			}
			PeakHeadTrackingPlugin.Logger.LogInfo((object)("Tracking " + (enabled ? "enabled" : "disabled")));
		}

		public void RecenterView()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			TrackingPose latestPose = coreReceiver.GetLatestPose();
			processor.RecenterTo(latestPose);
			interpolator.Reset();
			CameraPatches.RecenterPosition();
			PeakHeadTrackingPlugin.Logger.LogInfo((object)"View recentered");
		}

		private void OnDestroy()
		{
			SceneManager.sceneLoaded -= OnSceneLoaded;
			CameraPatches.UnregisterCameraCallback();
			if ((Object)(object)mainCamera != (Object)null)
			{
				ViewMatrixModifier.Reset(mainCamera);
			}
		}
	}
}