Decompiled source of OpenTrack Compatible Head Tracking for PEAK v1.0.2
plugins\CameraUnlock.Core.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.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
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.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 agousing 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); } } } }