Decompiled source of EchoLocation MM v2.0.0

Mods/EchoLocation.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BoneLib;
using BoneLib.BoneMenu;
using BoneLib.BoneMenu.UI;
using Echolocation;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSLZ.Bonelab;
using Il2CppSLZ.Marrow;
using Il2CppSLZ.Marrow.AI;
using Il2CppSLZ.Marrow.Audio;
using Il2CppSLZ.Marrow.Input;
using Il2CppSLZ.Marrow.Pool;
using Il2CppSLZ.Marrow.PuppetMasta;
using Il2CppSLZ.Marrow.Utilities;
using Il2CppSLZ.Rig;
using Il2CppSystem;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;
using UnityEngine.XR;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(EcholocationMod), "EchoLocation-MM", "2.0.0", "Echolocation", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Echolocation
{
	internal sealed class BlackoutView : IDisposable
	{
		internal const int BlackQueue = 4998;

		internal const int EchoQueue = 4999;

		private readonly Action<string> _warning;

		private Mesh? _mesh;

		private Material? _material;

		private int _attempts;

		private float _nextAttempt;

		private bool _disposed;

		private readonly Camera?[] _desktopCameras = (Camera?[])(object)new Camera[64];

		private readonly bool[] _knownDesktopCameras = new bool[64];

		private readonly Camera?[] _overlayCameras = (Camera?[])(object)new Camera[16];

		private Il2CppReferenceArray<Camera>? _cameraBuffer;

		private int _desktopCount;

		private int _overlayCount;

		private int _lastCameraCount = -1;

		private float _nextCameraRefresh;

		private bool _cameraWarning;

		internal bool Active { get; private set; }

		internal string Status { get; private set; } = "Waiting for player";

		internal BlackoutView(Action<string> warning)
		{
			_warning = warning;
		}

		internal void Tick(float now, bool enabled)
		{
			Active = false;
			if (_disposed)
			{
				return;
			}
			if (!enabled)
			{
				Status = "Normal vision";
				return;
			}
			GUIMenu instance = GUIMenu.Instance;
			UIRig uIRig = Player.UIRig;
			if (((Object)(object)uIRig != (Object)null && (Object)(object)uIRig.popUpMenu != (Object)null && uIRig.popUpMenu.isActive) || ((Object)(object)instance != (Object)null && ((Component)instance).gameObject.activeInHierarchy))
			{
				Status = "Normal vision while a game menu is open";
				return;
			}
			EnsureAssets(now);
			if ((Object)(object)_mesh == (Object)null || (Object)(object)_material == (Object)null)
			{
				return;
			}
			OpenControllerRig controllerRig = Player.ControllerRig;
			Il2CppReferenceArray<Camera> val = (((Object)(object)controllerRig != (Object)null) ? controllerRig.cameras : null);
			Camera main = Camera.main;
			RefreshDesktopCameras(now);
			bool flag = false;
			int num = 0;
			while (val != null && num < ((Il2CppArrayBase<Camera>)(object)val).Length)
			{
				Camera val2 = ((Il2CppArrayBase<Camera>)(object)val)[num];
				if ((Object)(object)val2 == (Object)(object)main)
				{
					flag = true;
				}
				DrawCamera(val2);
				num++;
			}
			if (!flag)
			{
				DrawCamera(main);
			}
			for (int i = 0; i < _desktopCount; i++)
			{
				Camera val3 = _desktopCameras[i];
				if ((Object)(object)val3 == (Object)null || (Object)(object)val3 == (Object)(object)main || (!_knownDesktopCameras[i] && !IsDisplayCamera(val3)))
				{
					continue;
				}
				bool flag2 = false;
				int num2 = 0;
				while (val != null && num2 < ((Il2CppArrayBase<Camera>)(object)val).Length)
				{
					if ((Object)(object)((Il2CppArrayBase<Camera>)(object)val)[num2] == (Object)(object)val3)
					{
						flag2 = true;
						break;
					}
					num2++;
				}
				if (!flag2)
				{
					DrawCamera(val3);
				}
			}
			Status = (Active ? "Blackout active: echolocation only" : "Waiting for player camera");
		}

		private void RefreshDesktopCameras(float now)
		{
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			int allCamerasCount = Camera.allCamerasCount;
			if (now < _nextCameraRefresh && allCamerasCount == _lastCameraCount)
			{
				return;
			}
			_nextCameraRefresh = now + 0.5f;
			_lastCameraCount = allCamerasCount;
			Array.Clear(_desktopCameras, 0, _desktopCameras.Length);
			Array.Clear(_overlayCameras, 0, _overlayCameras.Length);
			_desktopCount = (_overlayCount = 0);
			try
			{
				Il2CppArrayBase<RigScreenOptions> val = Object.FindObjectsOfType<RigScreenOptions>();
				for (int i = 0; i < val.Length && i < _overlayCameras.Length; i++)
				{
					RigScreenOptions val2 = val[i];
					if (!((Object)(object)val2 == (Object)null))
					{
						if ((Object)(object)val2.OverlayCam != (Object)null)
						{
							_overlayCameras[_overlayCount++] = val2.OverlayCam;
						}
						AddDesktopCamera(val2.cam, knownView: true);
					}
				}
				RigManager rigManager = Player.RigManager;
				PancakeControllerRig val3 = (((Object)(object)rigManager != (Object)null && (Object)(object)rigManager.controllerRig != (Object)null) ? ((Il2CppObjectBase)rigManager.controllerRig).TryCast<PancakeControllerRig>() : null);
				if ((Object)(object)val3 != (Object)null && (Object)(object)val3.wasdCam != (Object)null)
				{
					AddDesktopCamera(val3.wasdCam.Camera, knownView: true);
				}
				if (allCamerasCount < 1 || allCamerasCount > 1024)
				{
					return;
				}
				if (_cameraBuffer == null || ((Il2CppArrayBase<Camera>)(object)_cameraBuffer).Length < allCamerasCount)
				{
					_cameraBuffer = new Il2CppReferenceArray<Camera>((long)Math.Max(32, allCamerasCount));
				}
				allCamerasCount = Camera.GetAllCameras(_cameraBuffer);
				for (int j = 0; j < allCamerasCount; j++)
				{
					Camera val4 = ((Il2CppArrayBase<Camera>)(object)_cameraBuffer)[j];
					if ((Object)(object)val4 != (Object)null && IsDisplayCamera(val4))
					{
						AddDesktopCamera(val4, knownView: false);
					}
				}
			}
			catch (Exception ex)
			{
				if (!_cameraWarning)
				{
					_cameraWarning = true;
					_warning("Desktop blackout camera discovery will retry: " + ex.Message);
				}
			}
		}

		private static bool IsDisplayCamera(Camera camera)
		{
			if (!camera.stereoEnabled && (Object)(object)camera.targetTexture == (Object)null)
			{
				return camera.targetDisplay >= 0;
			}
			return false;
		}

		private void AddDesktopCamera(Camera? camera, bool knownView)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			if ((Object)(object)camera == (Object)null || !((Behaviour)camera).isActiveAndEnabled || (int)camera.cameraType != 1 || (camera.cullingMask & -33) == 0 || _desktopCount >= _desktopCameras.Length)
			{
				return;
			}
			for (int i = 0; i < _desktopCount; i++)
			{
				if ((Object)(object)_desktopCameras[i] == (Object)(object)camera)
				{
					return;
				}
			}
			_knownDesktopCameras[_desktopCount] = knownView;
			_desktopCameras[_desktopCount++] = camera;
		}

		private void DrawCamera(Camera? camera)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)camera == (Object)null || !((Behaviour)camera).isActiveAndEnabled || (int)camera.cameraType != 1 || (camera.cullingMask & -33) == 0)
			{
				return;
			}
			for (int i = 0; i < _overlayCount; i++)
			{
				if ((Object)(object)_overlayCameras[i] == (Object)(object)camera)
				{
					return;
				}
			}
			float num = Mathf.Max(2f, camera.nearClipPlane * 4f + camera.stereoSeparation);
			num = Mathf.Min(num, camera.farClipPlane * 0.4f);
			Matrix4x4 val = Matrix4x4.TRS(((Component)camera).transform.position, Quaternion.identity, Vector3.one * num);
			int num2 = VisibleLayer(camera.cullingMask);
			if (num2 >= 0)
			{
				Graphics.DrawMesh(_mesh, val, _material, num2, camera, 0, (MaterialPropertyBlock)null, (ShadowCastingMode)0, false, (Transform)null, (LightProbeUsage)0, (LightProbeProxyVolume)null);
				Active = true;
			}
		}

		internal void Reset()
		{
			Active = false;
			_attempts = 0;
			_nextAttempt = 0f;
			_lastCameraCount = -1;
			_nextCameraRefresh = 0f;
			_cameraWarning = false;
			_desktopCount = (_overlayCount = 0);
			Array.Clear(_desktopCameras, 0, _desktopCameras.Length);
			Array.Clear(_overlayCameras, 0, _overlayCameras.Length);
			_cameraBuffer = null;
			Status = "Waiting for player";
		}

		private void EnsureAssets(float now)
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Expected O, but got Unknown
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			if (((Object)(object)_mesh != (Object)null && (Object)(object)_material != (Object)null) || now < _nextAttempt)
			{
				return;
			}
			_attempts++;
			_nextAttempt = now + ((_attempts >= 6) ? 10f : 2f);
			DestroyAssets();
			string[] array = new string[2] { "Hidden/Internal-Colored", "GUI/Text Shader" };
			foreach (string text in array)
			{
				Shader val = Shader.Find(text);
				if ((Object)(object)val == (Object)null || !val.isSupported)
				{
					continue;
				}
				Material val2 = new Material(val)
				{
					hideFlags = (HideFlags)61,
					renderQueue = 4998
				};
				if (text == "Hidden/Internal-Colored" && (!val2.HasProperty("_ZTest") || !val2.HasProperty("_ZWrite")))
				{
					Object.Destroy((Object)(object)val2);
					continue;
				}
				_material = val2;
				if (val2.HasProperty("_Color"))
				{
					val2.SetColor("_Color", Color.black);
				}
				if (val2.HasProperty("_MainTex"))
				{
					val2.SetTexture("_MainTex", (Texture)(object)Texture2D.whiteTexture);
				}
				SetInt(val2, "_ZTest", 8);
				SetInt(val2, "_ZWrite", 0);
				SetInt(val2, "_Cull", 0);
				SetInt(val2, "_SrcBlend", 1);
				SetInt(val2, "_DstBlend", 0);
				_mesh = MakeCube();
				return;
			}
			Status = "Blackout shader unavailable";
			if (_attempts == 1 || _attempts == 6)
			{
				_warning("Blackout could not find an always-visible shader. F6 restores normal vision; check Echolocation diagnostics.");
			}
		}

		private static Mesh MakeCube()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_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_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: 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_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Expected O, but got Unknown
			Vector3[] array = (Vector3[])(object)new Vector3[8]
			{
				new Vector3(-1f, -1f, -1f),
				new Vector3(1f, -1f, -1f),
				new Vector3(1f, 1f, -1f),
				new Vector3(-1f, 1f, -1f),
				new Vector3(-1f, -1f, 1f),
				new Vector3(1f, -1f, 1f),
				new Vector3(1f, 1f, 1f),
				new Vector3(-1f, 1f, 1f)
			};
			int[] array2 = new int[36]
			{
				0, 2, 1, 0, 3, 2, 4, 5, 6, 4,
				6, 7, 0, 4, 7, 0, 7, 3, 1, 2,
				6, 1, 6, 5, 3, 7, 6, 3, 6, 2,
				0, 1, 5, 0, 5, 4
			};
			Il2CppStructArray<Vector3> val = new Il2CppStructArray<Vector3>((long)array.Length);
			Il2CppStructArray<Color> val2 = new Il2CppStructArray<Color>((long)array.Length);
			Il2CppStructArray<Vector2> val3 = new Il2CppStructArray<Vector2>((long)array.Length);
			Il2CppStructArray<int> val4 = new Il2CppStructArray<int>((long)(array2.Length * 2));
			for (int i = 0; i < array.Length; i++)
			{
				((Il2CppArrayBase<Vector3>)(object)val)[i] = array[i];
				((Il2CppArrayBase<Color>)(object)val2)[i] = Color.black;
				((Il2CppArrayBase<Vector2>)(object)val3)[i] = new Vector2(0.5f, 0.5f);
			}
			for (int j = 0; j < array2.Length; j += 3)
			{
				((Il2CppArrayBase<int>)(object)val4)[j] = array2[j];
				((Il2CppArrayBase<int>)(object)val4)[j + 1] = array2[j + 1];
				((Il2CppArrayBase<int>)(object)val4)[j + 2] = array2[j + 2];
				((Il2CppArrayBase<int>)(object)val4)[array2.Length + j] = array2[j];
				((Il2CppArrayBase<int>)(object)val4)[array2.Length + j + 1] = array2[j + 2];
				((Il2CppArrayBase<int>)(object)val4)[array2.Length + j + 2] = array2[j + 1];
			}
			Mesh val5 = new Mesh
			{
				name = "Echolocation.Blackout",
				hideFlags = (HideFlags)61
			};
			val5.SetVertices(val, 0, array.Length);
			val5.SetColors(val2, 0, array.Length);
			val5.SetUVs(0, val3, 0, array.Length);
			val5.SetTriangles(val4, 0, ((Il2CppArrayBase<int>)(object)val4).Length, 0, true, 0);
			return val5;
		}

		private static int VisibleLayer(int mask)
		{
			for (int i = 0; i < 32; i++)
			{
				if ((mask & (1 << i)) != 0)
				{
					return i;
				}
			}
			return -1;
		}

		private static void SetInt(Material material, string name, int value)
		{
			if (material.HasProperty(name))
			{
				material.SetInt(name, value);
			}
		}

		private void DestroyAssets()
		{
			if ((Object)(object)_mesh != (Object)null)
			{
				Object.Destroy((Object)(object)_mesh);
			}
			if ((Object)(object)_material != (Object)null)
			{
				Object.Destroy((Object)(object)_material);
			}
			_mesh = null;
			_material = null;
		}

		public void Dispose()
		{
			if (!_disposed)
			{
				_disposed = true;
				Reset();
				DestroyAssets();
			}
		}
	}
	internal sealed class BulletTrails : IDisposable
	{
		private struct Shot
		{
			public Vector3 Start;

			public Vector3 End;

			public float Birth;

			public float Lifetime;

			public float Distance;

			public bool Hit;
		}

		private readonly Settings _settings;

		private readonly MarkerBatch _batch;

		private readonly TimedHistory<Shot> _shots = new TimedHistory<Shot>(128);

		private readonly Il2CppStructArray<RaycastHit> _hits = new Il2CppStructArray<RaycastHit>(64L);

		private int _frame = -1;

		private int _frameShots;

		public int AcceptedShots { get; private set; }

		public BulletTrails(Settings settings, Action<string> warning)
		{
			_settings = settings;
			_batch = new MarkerBatch(warning);
		}

		public void RecordShot(Gun gun, float now, Transform head, Transform? localRoot)
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//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_007a: 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)
			//IL_0083: 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_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			if (!_settings.BulletTrails || (Object)(object)gun == (Object)null || (Object)(object)gun.firePointTransform == (Object)null)
			{
				return;
			}
			if (_frame != Time.frameCount)
			{
				_frame = Time.frameCount;
				_frameShots = 0;
			}
			if (_frameShots++ >= _settings.PlayerRayBudget * 2)
			{
				return;
			}
			Transform firePointTransform = gun.firePointTransform;
			Vector3 position = firePointTransform.position;
			Vector3 val = firePointTransform.forward;
			if (!PlayerTarget.Finite(position) || !PlayerTarget.Finite(val) || ((Vector3)(ref val)).sqrMagnitude < 0.01f)
			{
				return;
			}
			val = ((Vector3)(ref val)).normalized;
			if (Vector3.Distance(head.position, position) > _settings.PlayerRange)
			{
				return;
			}
			float num = _settings.TracerRange;
			bool flag = Vector3.Distance(head.position, position) < 2f;
			int num2 = Physics.RaycastNonAlloc(position, val, _hits, num, -5, (QueryTriggerInteraction)1);
			bool hit = false;
			for (int i = 0; i < num2; i++)
			{
				RaycastHit val2 = ((Il2CppArrayBase<RaycastHit>)(object)_hits)[i];
				if (!((Object)(object)((RaycastHit)(ref val2)).collider == (Object)null) && !(((RaycastHit)(ref val2)).distance <= 0.01f) && !(((RaycastHit)(ref val2)).distance >= num))
				{
					Transform transform = ((Component)((RaycastHit)(ref val2)).collider).transform;
					if (!((Object)(object)transform == (Object)(object)((Component)gun).transform) && !transform.IsChildOf(((Component)gun).transform) && (!flag || !((Object)(object)localRoot != (Object)null) || (!((Object)(object)transform == (Object)(object)localRoot) && !transform.IsChildOf(localRoot))))
					{
						num = ((RaycastHit)(ref val2)).distance;
						hit = true;
					}
				}
			}
			if (num2 < ((Il2CppArrayBase<RaycastHit>)(object)_hits).Length)
			{
				_shots.Add(new Shot
				{
					Start = position,
					End = position + val * num,
					Birth = now,
					Lifetime = _settings.TracerLifetime,
					Distance = num,
					Hit = hit
				}, now, _settings.TracerLifetime);
				AcceptedShots++;
			}
		}

		public void Tick(float now, Transform head)
		{
			//IL_0026: 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_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_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: 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_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: 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_00f0: 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_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//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_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: 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_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Unknown result type (might be due to invalid IL or missing references)
			//IL_027a: 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)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0314: Unknown result type (might be due to invalid IL or missing references)
			//IL_0319: Unknown result type (might be due to invalid IL or missing references)
			//IL_035a: Unknown result type (might be due to invalid IL or missing references)
			//IL_035c: Unknown result type (might be due to invalid IL or missing references)
			//IL_035f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0364: Unknown result type (might be due to invalid IL or missing references)
			//IL_0367: Unknown result type (might be due to invalid IL or missing references)
			//IL_0390: Unknown result type (might be due to invalid IL or missing references)
			//IL_0395: Unknown result type (might be due to invalid IL or missing references)
			if (!_settings.BulletTrails)
			{
				_shots.Clear();
				return;
			}
			_batch.Begin(now);
			Vector3 position = head.position;
			Vector3 right = head.right;
			Vector3 up = head.up;
			Camera main = Camera.main;
			float drawLimit = (((Object)(object)main != (Object)null) ? Mathf.Clamp(main.farClipPlane * 0.75f, 1f, 200f) : 200f);
			for (int i = 0; i < Math.Min(_shots.Count, _settings.TracerLimit); i++)
			{
				if (!_shots.TryGetNewest(i, now, out var item, out var _))
				{
					continue;
				}
				(float, float, float, float) tuple = TracerStyle.At(now - item.Birth, item.Distance, item.Lifetime);
				if (!(tuple.Item3 <= 0.001f))
				{
					float num = Vector3.Distance(position, (item.Start + item.End) * 0.5f);
					float num2 = LocatorMath.Projection(Math.Max(Vector3.Distance(position, item.Start), Vector3.Distance(position, item.End)), drawLimit);
					Vector3 val = position + (item.Start - position) * num2;
					Vector3 val2 = position + (item.End - position) * num2;
					Vector3 val3 = Vector3.Lerp(val, val2, tuple.Item1);
					Vector3 a = Vector3.Lerp(val, val2, tuple.Item2);
					float num3 = Math.Max(0.018f, num * 0.00055f) * num2;
					_batch.TaperedLine(a, val3, num3 * 0.2f, num3 * 3f, new Color(0.1f, 0.4f, 1f, 0f), new Color(0.15f, 0.8f, 1f, tuple.Item3 * 0.32f), position);
					_batch.TaperedLine(a, val3, num3 * 0.08f, num3, new Color(0.3f, 0.65f, 1f, tuple.Item3 * 0.08f), new Color(0.9f, 0.98f, 1f, tuple.Item3), position);
					float num4 = ((item.Hit && tuple.Item1 >= 1f) ? tuple.Item4 : tuple.Item3);
					if (num4 > 0.02f)
					{
						_batch.Line(val3 - right * num3 * 2f, val3 + right * num3 * 2f, num3 * 0.45f, new Color(1f, 0.97f, 0.8f, num4 * 0.8f), position);
						_batch.Line(val3 - up * num3 * 2f, val3 + up * num3 * 2f, num3 * 0.45f, new Color(1f, 0.97f, 0.8f, num4 * 0.8f), position);
					}
					if (item.Hit && tuple.Item4 > 0.02f)
					{
						float num5 = num3 * (2f + (1f - tuple.Item4) * 5f);
						_batch.Ring(val2, right * num5, up * num5, num3 * 0.4f, new Color(1f, 0.65f, 0.2f, tuple.Item4 * 0.5f), position);
					}
				}
			}
			_batch.Flush();
		}

		public void Reset()
		{
			_shots.Clear();
			_batch.Reset();
			_frame = -1;
			_frameShots = 0;
			AcceptedShots = 0;
		}

		public void Dispose()
		{
			Reset();
			_batch.Dispose();
		}
	}
	internal sealed class DesktopVoiceMeter : IDisposable
	{
		private readonly Settings _settings;

		private readonly bool _vr;

		private Material? _uiMaterial;

		private readonly Image?[] _segments = (Image?[])(object)new Image[28];

		private RectTransform? _peakMarker;

		private float _peak;

		private float _peakUntil;

		private GameObject? _root;

		private Canvas? _canvas;

		private RectTransform? _panel;

		private RectTransform? _casualMarker;

		private RectTransform? _loudMarker;

		private Text? _state;

		private Text? _values;

		private Text? _note;

		private Font? _font;

		private float _nextUpdate;

		private const float BarWidth = 340f;

		private static readonly Color Pink = new Color(1f, 0.39f, 0.55f, 1f);

		private static readonly Color Amber = new Color(1f, 0.79f, 0.2f, 1f);

		private static readonly Color Green = new Color(0.2f, 0.95f, 0.65f, 1f);

		public DesktopVoiceMeter(Settings settings, bool vr = false)
		{
			_settings = settings;
			_vr = vr;
		}

		public void Tick(float now, bool active, MicrophoneInput input)
		{
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c2: 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_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: 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_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_038f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0394: Unknown result type (might be due to invalid IL or missing references)
			//IL_0374: Unknown result type (might be due to invalid IL or missing references)
			//IL_036d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0366: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0406: Unknown result type (might be due to invalid IL or missing references)
			//IL_0413: Unknown result type (might be due to invalid IL or missing references)
			//IL_0425: Unknown result type (might be due to invalid IL or missing references)
			//IL_042a: Unknown result type (might be due to invalid IL or missing references)
			//IL_042e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0433: Unknown result type (might be due to invalid IL or missing references)
			//IL_043e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0443: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0455: Unknown result type (might be due to invalid IL or missing references)
			//IL_0541: Unknown result type (might be due to invalid IL or missing references)
			//IL_0568: Unknown result type (might be due to invalid IL or missing references)
			//IL_0578: Unknown result type (might be due to invalid IL or missing references)
			if (!active || !_settings.Enabled || !(_vr ? _settings.VrVoiceMeter : _settings.DesktopVoiceMeter))
			{
				Hide();
			}
			else if (!_vr && XRSettings.enabled && !XRSettings.showDeviceView)
			{
				Hide();
			}
			else
			{
				if (!float.IsFinite(now))
				{
					return;
				}
				Camera val = (_vr ? HeadsetCamera() : null);
				if (_vr && (Object)(object)val == (Object)null)
				{
					Hide();
					return;
				}
				if ((Object)(object)_root == (Object)null || (Object)(object)_canvas == (Object)null)
				{
					if (now < _nextUpdate)
					{
						return;
					}
					_nextUpdate = now + 5f;
					Build();
					_nextUpdate = now;
				}
				if (_vr)
				{
					_canvas.renderMode = (RenderMode)2;
					_canvas.worldCamera = val;
					int num = VoiceMeterPlacement.Layer(val.cullingMask);
					if (num < 0)
					{
						Hide();
						return;
					}
					if (_root.layer != num)
					{
						Il2CppArrayBase<Transform> componentsInChildren = _root.GetComponentsInChildren<Transform>(true);
						for (int i = 0; i < componentsInChildren.Length; i++)
						{
							((Component)componentsInChildren[i]).gameObject.layer = num;
						}
					}
					RectTransform component = _root.GetComponent<RectTransform>();
					component.sizeDelta = new Vector2(380f, 142f);
					float num2 = Math.Max(1.25f, val.nearClipPlane + 0.2f);
					((Transform)component).position = ((Component)val).transform.position + ((Component)val).transform.forward * num2 - ((Component)val).transform.up * (num2 * 0.224f);
					((Transform)component).rotation = ((Component)val).transform.rotation;
					((Transform)component).localScale = Vector3.one * (0.0015f * num2 / 1.25f);
					RectTransform? panel = _panel;
					RectTransform? panel2 = _panel;
					RectTransform? panel3 = _panel;
					Vector2 val2 = default(Vector2);
					((Vector2)(ref val2))..ctor(0.5f, 0.5f);
					panel3.pivot = val2;
					Vector2 anchorMin = (panel2.anchorMax = val2);
					panel.anchorMin = anchorMin;
					_panel.anchoredPosition = Vector2.zero;
					((Transform)_panel).localScale = Vector3.one;
				}
				else
				{
					if ((int)_canvas.renderMode != 0)
					{
						_canvas.renderMode = (RenderMode)0;
					}
					_canvas.worldCamera = null;
					_canvas.targetDisplay = 0;
					float num3 = Mathf.Clamp(Math.Min((float)Screen.width / 1000f, (float)Screen.height / 700f), 0.5f, 1.5f);
					((Transform)_panel).localScale = new Vector3(num3, num3, 1f);
				}
				if (!_root.activeSelf)
				{
					_root.SetActive(true);
				}
				if (now < _nextUpdate)
				{
					return;
				}
				_nextUpdate = now + 0.05f;
				bool available = VoiceMeterReading.IsFresh(now, input.SampleTime, VoiceMeterPlacement.Sample(_settings.MicrophoneEnabled, _settings.AnyVoiceMeter), input.HasLevel);
				VoiceMeterReading voiceMeterReading = new VoiceMeterReading(input.Level, _settings.VoiceRevealThreshold, _settings.VoiceLoudThreshold, available);
				Color color = (Color)((!voiceMeterReading.Available) ? new Color(0.5f, 0.58f, 0.66f, 1f) : (voiceMeterReading.Loud ? Pink : (voiceMeterReading.Detected ? Amber : Green)));
				for (int j = 0; j < _segments.Length; j++)
				{
					float num4 = (float)j / (float)_segments.Length;
					Color val4 = ((num4 >= voiceMeterReading.LoudMarker) ? Pink : ((num4 >= voiceMeterReading.CasualMarker) ? Amber : Green));
					float num5 = Math.Clamp((voiceMeterReading.Fill - num4) * (float)_segments.Length, 0f, 1f);
					Color val5 = Color.Lerp(new Color(val4.r * 0.17f, val4.g * 0.17f, val4.b * 0.17f, 1f), val4, num5);
					if (((Graphic)_segments[j]).color != val5)
					{
						((Graphic)_segments[j]).color = val5;
					}
				}
				if (!voiceMeterReading.Available)
				{
					_peak = 0f;
				}
				else if (voiceMeterReading.Fill >= _peak)
				{
					_peak = voiceMeterReading.Fill;
					_peakUntil = now + 0.6f;
				}
				else if (now > _peakUntil)
				{
					_peak = Math.Max(voiceMeterReading.Fill, _peak - 0.035f);
				}
				_peakMarker.anchoredPosition = new Vector2(20f + 340f * _peak, 60f);
				((Component)_peakMarker).gameObject.SetActive(voiceMeterReading.Available && _peak > 0.01f);
				_casualMarker.anchoredPosition = new Vector2(20f + 340f * voiceMeterReading.CasualMarker, 57f);
				_loudMarker.anchoredPosition = new Vector2(20f + 340f * voiceMeterReading.LoudMarker, 57f);
				((Graphic)_state).color = color;
				SetText(_state, (!voiceMeterReading.Available) ? "NO INPUT" : (voiceMeterReading.Loud ? "LOUD" : (voiceMeterReading.Detected ? "DETECTED" : "WHISPER")));
				SetText(_values, $"LEVEL {voiceMeterReading.Level:F3}    TALK {_settings.VoiceRevealThreshold:F3}    LOUD {_settings.VoiceLoudThreshold:F3}");
				string text = ((!voiceMeterReading.Available) ? input.Status : ((_settings.Mode == ScanMode.EchoLocation) ? "Your mic level; received chat volume can differ." : "Scan mode: voice does not reveal players."));
				SetText(_note, (text.Length > 54) ? (text.Substring(0, 51) + "...") : text);
			}
		}

		private static Camera? HeadsetCamera()
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Invalid comparison between Unknown and I4
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Invalid comparison between Unknown and I4
			OpenControllerRig controllerRig = Player.ControllerRig;
			Il2CppReferenceArray<Camera> val = ((controllerRig != null) ? controllerRig.cameras : null);
			if (val != null)
			{
				for (int i = 0; i < ((Il2CppArrayBase<Camera>)(object)val).Length; i++)
				{
					if ((Object)(object)((Il2CppArrayBase<Camera>)(object)val)[i] != (Object)null && VoiceMeterPlacement.Headset(((Behaviour)((Il2CppArrayBase<Camera>)(object)val)[i]).isActiveAndEnabled, ((Il2CppArrayBase<Camera>)(object)val)[i].stereoEnabled, XRSettings.enabled, (int)((Il2CppArrayBase<Camera>)(object)val)[i].stereoTargetEye > 0))
					{
						return ((Il2CppArrayBase<Camera>)(object)val)[i];
					}
				}
			}
			Camera main = Camera.main;
			if (!((Object)(object)main != (Object)null) || !VoiceMeterPlacement.Headset(((Behaviour)main).isActiveAndEnabled, main.stereoEnabled, XRSettings.enabled, (int)main.stereoTargetEye > 0))
			{
				return null;
			}
			return main;
		}

		private void Build()
		{
			//IL_0071: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Expected O, but got Unknown
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_0297: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_030c: Unknown result type (might be due to invalid IL or missing references)
			//IL_033e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0375: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_042f: Unknown result type (might be due to invalid IL or missing references)
			//IL_046b: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0539: Unknown result type (might be due to invalid IL or missing references)
			Destroy();
			try
			{
				_font = Resources.GetBuiltinResource<Font>("Arial.ttf");
			}
			catch (Exception)
			{
				_font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
			}
			if ((Object)(object)_font == (Object)null)
			{
				_font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
			}
			if ((Object)(object)_font == (Object)null)
			{
				throw new InvalidOperationException("Voice meter font unavailable.");
			}
			try
			{
				if (_vr)
				{
					_uiMaterial = new Material(Graphic.defaultGraphicMaterial)
					{
						hideFlags = (HideFlags)61,
						renderQueue = 5000
					};
					_uiMaterial.SetInt("unity_GUIZTestMode", 8);
					if (_uiMaterial.HasProperty("_ZWrite"))
					{
						_uiMaterial.SetInt("_ZWrite", 0);
					}
				}
				_root = new GameObject(_vr ? "EchoLocation.VrVoiceMeter" : "EchoLocation.DesktopVoiceMeter", (Type[])(object)new Type[1] { Il2CppType.Of<RectTransform>() });
				_root.SetActive(false);
				((Object)_root).hideFlags = (HideFlags)61;
				Object.DontDestroyOnLoad((Object)(object)_root);
				_canvas = _root.AddComponent<Canvas>();
				_canvas.renderMode = (RenderMode)(_vr ? 2 : 0);
				_canvas.worldCamera = null;
				_canvas.targetDisplay = 0;
				_canvas.sortingOrder = 32700;
				_panel = Rect(_root.transform, "Panel", 22f, 22f, 380f, 142f);
				Paint(_panel, new Color(0.17f, 0.24f, 0.31f, 0.95f));
				Paint(Rect((Transform)(object)_panel, "Background", 1f, 1f, 378f, 140f), new Color(0.018f, 0.026f, 0.045f, 0.97f));
				Paint(Rect((Transform)(object)_panel, "Accent", 0f, 108f, 3f, 26f), Pink);
				Label((Transform)(object)_panel, "Title", "VOICE LEVEL", 20f, 105f, 185f, 25f, 18, Color.white);
				Paint(Rect((Transform)(object)_panel, "Badge", 248f, 105f, 112f, 25f), new Color(0.07f, 0.1f, 0.14f, 1f));
				_state = Label((Transform)(object)_panel, "State", "WHISPER", 252f, 105f, 104f, 25f, 14, Green);
				_state.alignment = (TextAnchor)4;
				Label((Transform)(object)_panel, "WhisperLegend", "WHISPER", 20f, 84f, 110f, 17f, 10, Green);
				Label((Transform)(object)_panel, "TalkLegend", "TALK", 143f, 84f, 90f, 17f, 10, Amber).alignment = (TextAnchor)4;
				Label((Transform)(object)_panel, "LoudLegend", "LOUD", 270f, 84f, 90f, 17f, 10, Pink).alignment = (TextAnchor)5;
				for (int i = 0; i < _segments.Length; i++)
				{
					_segments[i] = Paint(Rect((Transform)(object)_panel, "Segment" + i, 20f + 340f * (float)i / (float)_segments.Length, 60f, 340f / (float)_segments.Length - 3f, 20f), Green);
				}
				_casualMarker = Rect((Transform)(object)_panel, "TalkThreshold", 20f, 57f, 2f, 26f);
				Paint(_casualMarker, Amber);
				_loudMarker = Rect((Transform)(object)_panel, "LoudThreshold", 20f, 57f, 2f, 26f);
				Paint(_loudMarker, Pink);
				_peakMarker = Rect((Transform)(object)_panel, "Peak", 20f, 60f, 2f, 20f);
				Paint(_peakMarker, Color.white);
				_values = Label((Transform)(object)_panel, "Values", "", 20f, 30f, 345f, 22f, 12, new Color(0.86f, 0.91f, 0.98f, 1f));
				_note = Label((Transform)(object)_panel, "InputStatus", "", 20f, 9f, 345f, 18f, 11, new Color(0.56f, 0.65f, 0.77f, 1f));
			}
			catch
			{
				Destroy();
				throw;
			}
		}

		private static RectTransform Rect(Transform parent, string name, float x, float y, float width, float height)
		{
			//IL_000f: 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)
			//IL_0030: 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_0038: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			RectTransform component = new GameObject(name, (Type[])(object)new Type[1] { Il2CppType.Of<RectTransform>() }).GetComponent<RectTransform>();
			((Transform)component).SetParent(parent, false);
			Vector2 val = (component.pivot = Vector2.zero);
			Vector2 anchorMin = (component.anchorMax = val);
			component.anchorMin = anchorMin;
			component.anchoredPosition = new Vector2(x, y);
			component.sizeDelta = new Vector2(width, height);
			return component;
		}

		private Image Paint(RectTransform rect, Color color)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			Image val = ((Component)rect).gameObject.AddComponent<Image>();
			((Graphic)val).color = color;
			((Graphic)val).raycastTarget = false;
			if ((Object)(object)_uiMaterial != (Object)null)
			{
				((Graphic)val).material = _uiMaterial;
			}
			return val;
		}

		private Text Label(Transform parent, string name, string value, float x, float y, float width, float height, int size, Color color)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			Text val = ((Component)Rect(parent, name, x, y, width, height)).gameObject.AddComponent<Text>();
			val.font = _font;
			val.fontSize = size;
			val.fontStyle = (FontStyle)(size >= 16);
			((Graphic)val).color = color;
			val.alignment = (TextAnchor)3;
			((Graphic)val).raycastTarget = false;
			val.supportRichText = false;
			val.horizontalOverflow = (HorizontalWrapMode)1;
			val.verticalOverflow = (VerticalWrapMode)0;
			if ((Object)(object)_uiMaterial != (Object)null)
			{
				((Graphic)val).material = _uiMaterial;
			}
			val.text = value;
			return val;
		}

		private static void SetText(Text text, string value)
		{
			if (text.text != value)
			{
				text.text = value;
			}
		}

		public void Hide()
		{
			if ((Object)(object)_root != (Object)null && _root.activeSelf)
			{
				_root.SetActive(false);
			}
			_peak = 0f;
			_peakUntil = 0f;
		}

		public void Reset()
		{
			Hide();
			Destroy();
			_nextUpdate = 0f;
		}

		private void Destroy()
		{
			if ((Object)(object)_root != (Object)null)
			{
				_root.SetActive(false);
				Object.Destroy((Object)(object)_root);
			}
			if ((Object)(object)_uiMaterial != (Object)null)
			{
				Object.Destroy((Object)(object)_uiMaterial);
			}
			_root = null;
			_canvas = null;
			_uiMaterial = null;
			Array.Clear(_segments, 0, _segments.Length);
		}

		public void Dispose()
		{
			Destroy();
		}
	}
	internal enum DotShape
	{
		Circle,
		Triangle,
		Square
	}
	internal enum RadarDirection
	{
		Inward,
		Outward
	}
	internal enum RadarTargetKind
	{
		Scenery,
		Player,
		Object,
		Npc
	}
	internal static class RadarPolicy
	{
		internal static RadarTargetKind Classify(bool player, bool npc, bool physicsObject)
		{
			if (!player)
			{
				if (!npc)
				{
					if (!physicsObject)
					{
						return RadarTargetKind.Scenery;
					}
					return RadarTargetKind.Object;
				}
				return RadarTargetKind.Npc;
			}
			return RadarTargetKind.Player;
		}

		internal static bool AcceptsContact(RadarTargetKind kind, bool contact, bool players, bool objects, bool npcs)
		{
			if (Allows(kind, players, objects, npcs))
			{
				return kind == RadarTargetKind.Scenery || contact;
			}
			return false;
		}

		internal static bool Allows(RadarTargetKind kind, bool players, bool objects, bool npcs)
		{
			return kind switch
			{
				RadarTargetKind.Player => players, 
				RadarTargetKind.Object => objects, 
				RadarTargetKind.Npc => npcs, 
				_ => true, 
			};
		}
	}
	internal static class DotShapes
	{
		internal static DotShape Valid(DotShape shape)
		{
			if (shape < DotShape.Circle || shape > DotShape.Square)
			{
				return DotShape.Circle;
			}
			return shape;
		}

		internal static (float X, float Y) Boundary(int index, DotShape shape)
		{
			int num;
			switch (shape)
			{
			case DotShape.Circle:
			{
				float x = (float)index * 2f * (float)Math.PI / 12f;
				return (X: MathF.Cos(x), Y: MathF.Sin(x));
			}
			default:
				num = 4;
				break;
			case DotShape.Triangle:
				num = 3;
				break;
			}
			int num2 = num;
			int num3 = 12 / num2;
			int num4 = index / num3;
			float num5 = (float)(index % num3) / (float)num3;
			(float, float) tuple = Corner(num4, shape);
			(float, float) tuple2 = Corner((num4 + 1) % num2, shape);
			return (X: tuple.Item1 + (tuple2.Item1 - tuple.Item1) * num5, Y: tuple.Item2 + (tuple2.Item2 - tuple.Item2) * num5);
		}

		private static (float X, float Y) Corner(int i, DotShape shape)
		{
			(int, int) tuple = ((shape != DotShape.Triangle) ? (i switch
			{
				0 => (-1, -1), 
				1 => (1, -1), 
				2 => (1, 1), 
				_ => (-1, 1), 
			}) : (i switch
			{
				0 => (0, 1), 
				1 => (-1, -1), 
				_ => (1, -1), 
			}));
			(int, int) tuple2 = tuple;
			return (X: tuple2.Item1, Y: tuple2.Item2);
		}
	}
	internal static class DotTexture
	{
		public static float Alpha(float u, float v, DotShape shape = DotShape.Circle)
		{
			float num = u * 2f - 1f;
			float num2 = v * 2f - 1f;
			float num3 = Math.Clamp(1f - shape switch
			{
				DotShape.Square => Math.Max(Math.Abs(num), Math.Abs(num2)), 
				DotShape.Triangle => Math.Max(0f - num2, Math.Max(2f * num + num2, -2f * num + num2)), 
				_ => MathF.Sqrt(num * num + num2 * num2), 
			}, 0f, 1f);
			return num3 * num3 * (3f - 2f * num3);
		}
	}
	internal sealed class DoubleClapGesture
	{
		private const float MinimumClapInterval = 0.12f;

		private const float MaximumClapInterval = 1.5f;

		private const float PulseCooldown = 0.6f;

		private const float MaximumSampleGap = 0.3f;

		private bool _initialized;

		private bool _armed;

		private bool _hasFirstClap;

		private Vector3 _lastLeft;

		private Vector3 _lastRight;

		private float _lastTime;

		private float _lastDistance;

		private float _firstClapTime;

		private float _nextPulseTime;

		private float _lastContactDistance;

		internal bool ContactDetected { get; private set; }

		public bool Tick(float now, Vector3 left, Vector3 right, bool available, float contactDistance = 0.3f)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: 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_00cc: 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_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: 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)
			ContactDetected = false;
			if (!available || !float.IsFinite(now) || !Finite(left) || !Finite(right))
			{
				Reset();
				return false;
			}
			float num = Vector3.Distance(left, right);
			if (!float.IsFinite(num))
			{
				Reset();
				return false;
			}
			contactDistance = (float.IsFinite(contactDistance) ? Math.Clamp(contactDistance, 0.15f, 0.45f) : 0.3f);
			float num2 = contactDistance + 0.1f;
			float num3 = now - _lastTime;
			float num4 = Math.Max(0.6f, num3 * 14f);
			if (!_initialized || contactDistance != _lastContactDistance || num3 <= 0f || num3 > 0.3f || Vector3.Distance(left, _lastLeft) > num4 || Vector3.Distance(right, _lastRight) > num4)
			{
				BeginSample(now, left, right, num, contactDistance);
				return false;
			}
			bool flag = _lastDistance > contactDistance && num <= contactDistance;
			_lastTime = now;
			_lastLeft = left;
			_lastRight = right;
			_lastDistance = num;
			if (_hasFirstClap && now - _firstClapTime > 1.5f)
			{
				_hasFirstClap = false;
			}
			if (now < _nextPulseTime)
			{
				_armed = false;
				_hasFirstClap = false;
				return false;
			}
			if (num >= num2)
			{
				_armed = true;
			}
			if (!_armed || !flag)
			{
				return false;
			}
			_armed = false;
			if (!_hasFirstClap)
			{
				_hasFirstClap = true;
				_firstClapTime = now;
				ContactDetected = true;
				return false;
			}
			if (now - _firstClapTime < 0.12f)
			{
				return false;
			}
			_hasFirstClap = false;
			_nextPulseTime = now + 0.6f;
			ContactDetected = true;
			return true;
		}

		private void BeginSample(float now, Vector3 left, Vector3 right, float distance, float contactDistance)
		{
			//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_0032: 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)
			if (_initialized && now < _lastTime)
			{
				_nextPulseTime = 0f;
			}
			_initialized = true;
			_lastTime = now;
			_lastLeft = left;
			_lastRight = right;
			_lastDistance = distance;
			_lastContactDistance = contactDistance;
			_armed = distance >= contactDistance + 0.1f && now >= _nextPulseTime;
			_hasFirstClap = false;
		}

		private static bool Finite(Vector3 value)
		{
			//IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			if (float.IsFinite(value.x) && float.IsFinite(value.y))
			{
				return float.IsFinite(value.z);
			}
			return false;
		}

		public void Reset()
		{
			ContactDetected = false;
			_initialized = false;
			_armed = false;
			_hasFirstClap = false;
			_nextPulseTime = 0f;
		}
	}
	internal readonly struct EchoEvent
	{
		public Vector3 Origin { get; }

		public float Strength { get; }

		public float VoiceLevel { get; }

		public EchoKind Kind { get; }

		public float Time { get; }

		public int PlayerId { get; }

		public AudioSource? Source { get; }

		public NpcSoundEmission? NpcEmission { get; }

		public SoundEmitterSurface? SurfaceEmission { get; }

		public EchoEvent(Vector3 origin, float strength, EchoKind kind, float time, int playerId = -1, AudioSource? source = null, NpcSoundEmission? npcEmission = null, SoundEmitterSurface? surfaceEmission = null, float voiceLevel = 0f)
		{
			//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)
			Origin = origin;
			Strength = (float.IsFinite(strength) ? Mathf.Clamp01(strength) : 0f);
			VoiceLevel = (float.IsFinite(voiceLevel) ? Mathf.Clamp01(voiceLevel) : 0f);
			Kind = kind;
			Time = time;
			PlayerId = playerId;
			Source = source;
			NpcEmission = npcEmission;
			SurfaceEmission = surfaceEmission ?? npcEmission;
		}

		internal EchoEvent WithTime(float time)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return new EchoEvent(Origin, Strength, Kind, time, PlayerId, Source, NpcEmission, SurfaceEmission, VoiceLevel);
		}
	}
	internal enum EchoKind
	{
		Manual,
		Microphone,
		Footstep,
		World,
		Voice,
		Ambient
	}
	public sealed class EcholocationMod : MelonMod
	{
		private Settings _settings;

		private readonly StartupGate _startup = new StartupGate();

		private bool _runtimeReady;

		private bool _runtimeFailed;

		private bool _stopping;

		private bool _gunHooked;

		private ImpactSurfaceGlow _impactGlow;

		private readonly ScanCoverage _coverage = new ScanCoverage();

		private EchoRenderer _renderer;

		private MicrophoneInput _microphone;

		private WorldSoundInput _world;

		private ObjectSoundSources _objectSources;

		private WorldAudioMonitor _worldMonitor;

		private LocomotionInput _locomotion;

		private MenuPage _menu;

		private PulseAudio _audio;

		private BulletTrails _bulletTrails;

		private DesktopVoiceMeter _voiceMeter;

		private DesktopVoiceMeter _vrVoiceMeter;

		private readonly PulseShortcutInput _shortcut = new PulseShortcutInput();

		private Action<EchoEvent> _emit;

		private Action<EchoEvent> _observeSound;

		private Transform? _head;

		private Transform? _rigRoot;

		private bool _active;

		private float _nextWarning;

		private float _nextPulse;

		private readonly int[] _counts = new int[5];

		private readonly EchoEvent[] _pending = new EchoEvent[5];

		private readonly bool[] _hasPending = new bool[5];

		private int _inputCursor = 1;

		private readonly DoubleClapGesture _clap = new DoubleClapGesture();

		private int _clapPulseCount;

		public override void OnInitializeMelon()
		{
			_settings = new Settings();
			_menu = new MenuPage(_settings, this, Warn);
			_emit = Emit;
			_observeSound = ObserveSound;
			((MelonBase)this).LoggerInstance.Msg("EchoLocation-MM 2.0.0 loaded. Sound-only EchoLocation by default; optional Continuous Surroundings in Performance. Optional VR/spectator voice meters in General; normal speech reveals, loud speech brightens. LiDAR: double right grip.");
			((MelonBase)this).LoggerInstance.Msg("Visuals are local. Mic loudness is measured in memory only; no audio is saved or sent by this mod.");
			Save();
		}

		private bool EnsureRuntime()
		{
			if (_runtimeReady)
			{
				return true;
			}
			if (_runtimeFailed || _stopping)
			{
				return false;
			}
			try
			{
				_renderer = new EchoRenderer(_settings, Warn, _coverage);
				_microphone = new MicrophoneInput(_settings, Warn, _coverage);
				_objectSources = new ObjectSoundSources(Warn);
				_world = new WorldSoundInput(_settings, Warn, _objectSources.Capture);
				_locomotion = new LocomotionInput(_settings);
				_audio = new PulseAudio(Warn);
				_bulletTrails = new BulletTrails(_settings, Warn);
				_impactGlow = new ImpactSurfaceGlow(_settings, () => (!_active) ? null : _head, Warn);
				_voiceMeter = new DesktopVoiceMeter(_settings);
				_vrVoiceMeter = new DesktopVoiceMeter(_settings, vr: true);
				Hooking.OnPostFireGun += OnGunShot;
				_gunHooked = true;
				_worldMonitor = new WorldAudioMonitor(RegisterWorldPlayback, Warn);
				_runtimeReady = true;
				((MelonBase)this).LoggerInstance.Msg("Gameplay components ready after stable player rig.");
				return true;
			}
			catch (Exception ex)
			{
				DisposeRuntime();
				_runtimeFailed = true;
				_settings.Enabled = false;
				Save();
				Warn("Gameplay initialization stopped safely: " + ex.Message + ". Toggle On/Off to retry after loading.");
				return false;
			}
		}

		private void DisposeRuntime()
		{
			_active = (_runtimeReady = false);
			if (_gunHooked)
			{
				Hooking.OnPostFireGun -= OnGunShot;
				_gunHooked = false;
			}
			Release(_voiceMeter);
			Release(_vrVoiceMeter);
			Release(_impactGlow);
			Release(_bulletTrails);
			Release(_worldMonitor);
			Release(_microphone);
			Release(_world);
			Release(_renderer);
			Release(_audio);
			_voiceMeter = null;
			_vrVoiceMeter = null;
			_impactGlow = null;
			_bulletTrails = null;
			_worldMonitor = null;
			_microphone = null;
			_world = null;
			_renderer = null;
			_audio = null;
			_objectSources = null;
			_locomotion = null;
			void Release(IDisposable? part)
			{
				try
				{
					part?.Dispose();
				}
				catch (Exception ex)
				{
					((MelonBase)this).LoggerInstance.Warning("Cleanup: " + ex.Message);
				}
			}
		}

		public override void OnUpdate()
		{
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			if (_settings == null || _stopping)
			{
				return;
			}
			_menu.EnsureBuilt();
			if (_settings.DesktopHotkeys)
			{
				if (Input.GetKeyDown((KeyCode)287))
				{
					SetEnabled(!_settings.Enabled);
				}
				if (Input.GetKeyDown((KeyCode)286))
				{
					ManualPulse();
				}
			}
			Transform val = null;
			Transform val2 = null;
			try
			{
				val = Player.Head;
				if ((Object)(object)Player.RigManager != (Object)null)
				{
					val2 = ((Component)Player.RigManager).transform;
				}
			}
			catch (Exception)
			{
			}
			if (!_settings.Enabled || (Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || !((Component)val).gameObject.activeInHierarchy || !((Component)val2).gameObject.activeInHierarchy)
			{
				_clap.Reset();
				_startup.Reset();
				_shortcut.Reset();
				if (_active)
				{
					ResetState();
				}
				return;
			}
			if (_active && ((Object)(object)_head != (Object)(object)val || (Object)(object)_rigRoot != (Object)(object)val2))
			{
				ResetState();
			}
			if (!_startup.Ready(Time.unscaledTime, ((Object)val).GetInstanceID(), ((Object)val2).GetInstanceID()) || !EnsureRuntime())
			{
				return;
			}
			_head = val;
			_rigRoot = val2;
			_active = true;
			float unscaledTime = Time.unscaledTime;
			ReadPulseShortcut(unscaledTime, val);
			bool flag = _settings.Mode == ScanMode.EchoLocation;
			try
			{
				_microphone.Tick(unscaledTime, val.position, _emit, _observeSound, !flag);
			}
			catch (Exception ex2)
			{
				Warn("Microphone/voice input: " + ex2.Message);
			}
			if (!flag)
			{
				return;
			}
			try
			{
				if (_settings.Mode == ScanMode.EchoLocation)
				{
					_locomotion.Tick(unscaledTime, val, val2, _emit);
				}
			}
			catch (Exception ex3)
			{
				Warn("Footstep input: " + ex3.Message);
			}
			try
			{
				if (_settings.WorldSoundEnabled)
				{
					_worldMonitor.Tick(unscaledTime);
				}
				else
				{
					_worldMonitor?.Reset();
				}
			}
			catch (Exception ex4)
			{
				Warn("World playback monitoring: " + ex4.Message);
			}
			try
			{
				_world.Tick(unscaledTime, val.position, _emit, _observeSound);
			}
			catch (Exception ex5)
			{
				Warn("World sound input: " + ex5.Message);
			}
			FlushInput(unscaledTime);
		}

		public override void OnLateUpdate()
		{
			if (_stopping || !_runtimeReady)
			{
				return;
			}
			if (_voiceMeter != null && _settings != null)
			{
				try
				{
					_voiceMeter.Tick(Time.unscaledTime, _active && (Object)(object)_head != (Object)null, _microphone);
				}
				catch (Exception ex)
				{
					Warn("Desktop voice meter: " + ex.Message);
				}
				try
				{
					_vrVoiceMeter.Tick(Time.unscaledTime, _active && (Object)(object)_head != (Object)null, _microphone);
				}
				catch (Exception ex2)
				{
					Warn("VR voice meter: " + ex2.Message);
				}
			}
			if (!_active || !_settings.Enabled || (Object)(object)_head == (Object)null)
			{
				return;
			}
			try
			{
				_renderer.Tick(Time.unscaledTime, _head, _rigRoot);
			}
			catch (Exception ex3)
			{
				Warn("Surface renderer: " + ex3.Message);
			}
			try
			{
				_impactGlow.Tick(Time.unscaledTime);
			}
			catch (Exception ex4)
			{
				Warn("Impact glow renderer: " + ex4.Message);
			}
			try
			{
				_bulletTrails.Tick(Time.unscaledTime, _head);
			}
			catch (Exception ex5)
			{
				Warn("Bullet trail renderer: " + ex5.Message);
			}
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			if (_settings != null)
			{
				ResetState();
			}
		}

		public override void OnDeinitializeMelon()
		{
			_stopping = true;
			ResetState();
			DisposeRuntime();
			if (_settings != null)
			{
				Save();
			}
		}

		internal void SetEnabled(bool enabled)
		{
			_settings.Enabled = enabled;
			if (enabled)
			{
				_runtimeFailed = false;
			}
			if (!enabled)
			{
				ResetState();
			}
			Save();
		}

		internal void SetMode(ScanMode mode)
		{
			if (_settings.Mode != mode)
			{
				_settings.Mode = mode;
				ResetState();
				Save();
			}
		}

		internal void SetBlackout(bool enabled)
		{
			_settings.Blackout = enabled;
			Save();
		}

		internal void SetDoubleClap(bool enabled)
		{
			_settings.DoubleClapEnabled = enabled;
			_clap.Reset();
			Save();
		}

		internal void SetClapDistance(float distance)
		{
			_settings.ClapContactDistance = distance;
			_clap.Reset();
			Save();
		}

		internal void SetPulseSound(bool enabled)
		{
			_settings.PulseSoundEnabled = enabled;
			if (!enabled)
			{
				_audio?.Stop();
			}
			Save();
		}

		internal void TestPulseSound()
		{
			if (_runtimeReady && _active)
			{
				_audio.PlayPulse(_settings.PulseSoundVolume);
			}
		}

		private void OnGunShot(Gun gun)
		{
			if (!_active || _settings == null || !_settings.Enabled || (Object)(object)_head == (Object)null)
			{
				return;
			}
			try
			{
				_bulletTrails.RecordShot(gun, Time.unscaledTime, _head, _rigRoot);
			}
			catch (Exception ex)
			{
				Warn("Bullet trail: " + ex.Message);
			}
		}

		private void ReadPulseShortcut(float now, Transform head)
		{
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			PulseShortcut activeShortcut = _settings.ActiveShortcut;
			if (_settings.ShortcutActive)
			{
				switch (activeShortcut)
				{
				case PulseShortcut.Disabled:
					break;
				case PulseShortcut.DoubleClap:
					_shortcut.Reset();
					ReadClapGesture(now, head);
					return;
				default:
					_clap.Reset();
					try
					{
						OpenControllerRig controllerRig = Player.ControllerRig;
						BaseController leftController = Player.LeftController;
						BaseController rightController = Player.RightController;
						UIRig uIRig = Player.UIRig;
						GUIMenu instance = GUIMenu.Instance;
						XRApi xr = MarrowGame.xr;
						XRController val = ((xr != null) ? xr.LeftController : null);
						XRController val2 = ((xr != null) ? xr.RightController : null);
						bool flag = (Object)(object)controllerRig != (Object)null && !((ControllerRig)controllerRig).IsPaused && (Object)(object)leftController != (Object)null && (Object)(object)rightController != (Object)null && ((Behaviour)leftController).isActiveAndEnabled && ((Behaviour)rightController).isActiveAndEnabled && val != null && val2 != null && (!((Object)(object)uIRig != (Object)null) || !((Object)(object)uIRig.popUpMenu != (Object)null) || !uIRig.popUpMenu.isActive) && (!((Object)(object)instance != (Object)null) || !((Component)instance).gameObject.activeInHierarchy);
						if (_shortcut.Tick(now, activeShortcut, flag, flag && val.AButton, flag && val.BButton, flag && val.TriggerButton, flag && val2.TriggerButton, flag && val2.GripButton) && ((_settings.Mode == ScanMode.LiDAR) ? _renderer.EnqueueLidar(head.position, head.rotation, now) : _renderer.EnqueueClap(head.position, now)))
						{
							_clapPulseCount++;
							if (_settings.PulseSoundEnabled)
							{
								_audio.PlayPulse(_settings.PulseSoundVolume);
							}
						}
						return;
					}
					catch (Exception ex)
					{
						_shortcut.Reset();
						Warn("Pulse shortcut: " + ex.Message);
						return;
					}
				}
			}
			_shortcut.Reset();
			_clap.Reset();
		}

		private void ReadClapGesture(float now, Transform head)
		{
			//IL_00ff: 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_01b7: Unknown result type (might be due to invalid IL or missing references)
			if (!_settings.DoubleClapEnabled)
			{
				_clap.Reset();
				return;
			}
			try
			{
				OpenControllerRig controllerRig = Player.ControllerRig;
				BaseController leftController = Player.LeftController;
				BaseController rightController = Player.RightController;
				UIRig uIRig = Player.UIRig;
				GUIMenu instance = GUIMenu.Instance;
				if (((Object)(object)uIRig != (Object)null && (Object)(object)uIRig.popUpMenu != (Object)null && uIRig.popUpMenu.isActive) || ((Object)(object)instance != (Object)null && ((Component)instance).gameObject.activeInHierarchy) || !((Object)(object)controllerRig != (Object)null) || ((ControllerRig)controllerRig).IsPaused || !((Object)(object)leftController != (Object)null) || !((Object)(object)rightController != (Object)null) || !((Behaviour)leftController).isActiveAndEnabled || !((Behaviour)rightController).isActiveAndEnabled || !Player.HandsExist || Player.LeftHand.HasAttachedObject() || Player.RightHand.HasAttachedObject() || (Player.LeftHand._indexButton && Player.RightHand._indexButton))
				{
					_clap.Reset();
					return;
				}
				if (!_clap.Tick(now, ((Component)leftController).transform.position, ((Component)rightController).transform.position, available: true, _settings.ClapContactDistance))
				{
					if (_clap.ContactDetected && _settings.PulseSoundEnabled)
					{
						_audio.PlayClap(_settings.PulseSoundVolume);
					}
					return;
				}
				Transform val = head;
				if (controllerRig.cameras != null)
				{
					foreach (Camera item in (Il2CppArrayBase<Camera>)(object)controllerRig.cameras)
					{
						if ((Object)(object)item != (Object)null && ((Behaviour)item).isActiveAndEnabled)
						{
							val = ((Component)item).transform;
							break;
						}
					}
				}
				if (_renderer.EnqueueClap(val.position, now))
				{
					_clapPulseCount++;
					if (_settings.PulseSoundEnabled)
					{
						_audio.PlayPulse(_settings.PulseSoundVolume);
					}
				}
			}
			catch (Exception ex)
			{
				_clap.Reset();
				Warn("Double-clap input: " + ex.Message);
			}
		}

		internal void ManualPulse()
		{
			//IL_0064: 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_0094: 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)
			if (!_settings.Enabled || !_active || !_runtimeReady)
			{
				return;
			}
			try
			{
				Transform head = Player.Head;
				if (!((Object)(object)head != (Object)null))
				{
					return;
				}
				if (_settings.Mode == ScanMode.Radar)
				{
					_renderer.RestartRadar();
				}
				else if (_settings.Mode == ScanMode.Sonar)
				{
					_renderer.EnqueueSonar(head.position, Time.unscaledTime);
				}
				else if (_settings.Mode == ScanMode.LiDAR)
				{
					if (_renderer.EnqueueLidar(head.position, head.rotation, Time.unscaledTime) && _settings.PulseSoundEnabled)
					{
						_audio.PlayPulse(_settings.PulseSoundVolume);
					}
				}
				else if (_settings.Mode == ScanMode.EchoLocation)
				{
					Emit(new EchoEvent(head.position, 1f, EchoKind.Manual, Time.unscaledTime));
				}
			}
			catch (Exception ex)
			{
				Warn("Manual pulse needs a loaded player rig: " + ex.Message);
			}
		}

		internal void RestartMicrophone()
		{
			_microphone?.Restart();
		}

		internal void Diagnostics()
		{
			if (!_runtimeReady)
			{
				((MelonBase)this).LoggerInstance.Msg("EchoLocation waiting for a stable loaded player rig; no gameplay components are running.");
				return;
			}
			((MelonBase)this).LoggerInstance.Msg($"Enabled={_settings.Enabled}; mode={_settings.Mode}; rig={_active}; renderer={_renderer.Ready}; dots={_renderer.DotCount}");
			((MelonBase)this).LoggerInstance.Msg($"Vision: {_renderer.VisionStatus}; blackout setting={_settings.Blackout}");
			((MelonBase)this).LoggerInstance.Msg($"Players: {_renderer.PlayerStatus}; highlights={_settings.PlayerHighlights}");
			((MelonBase)this).LoggerInstance.Msg($"Echo player reveal: running enabled={_settings.RunningReveal}, speed >= {_settings.MovementThreshold:F1}m/s; voice level >= {_settings.VoiceRevealThreshold:F3}, brightest >= {_settings.VoiceLoudThreshold:F3}; fade={_settings.PlayerRevealLifetime:F1}s; scanners require a scan hit, fade={_settings.ScanPlayerLifetime:F1}s");
			((MelonBase)this).LoggerInstance.Msg($"Continuous surroundings={_settings.ContinuousSurroundings}; refresh={_settings.SurroundingsInterval:F1}s");
			((MelonBase)this).LoggerInstance.Msg($"Shortcut={_settings.Shortcut}; enabled={_settings.DoubleClapEnabled}; 360 pulses={_clapPulseCount}");
			((MelonBase)this).LoggerInstance.Msg($"Player/voice cap={_settings.PlayerRange:F0}m; beyond live dots={_settings.DetectionMargin:F1}m; coverage cells={_coverage.CellCount}; footprints={_settings.PlayerFootprints}");
			((MelonBase)this).LoggerInstance.Msg(_renderer.PerformanceStatus);
			((MelonBase)this).LoggerInstance.Msg($"Bullet trails={_settings.BulletTrails}; captured shots={_bulletTrails.AcceptedShots}; history limit={_settings.TracerLimit}; trace range={_settings.TracerRange:F0}m");
			((MelonBase)this).LoggerInstance.Msg($"Pulse sound enabled={_settings.PulseSoundEnabled}; volume={_settings.PulseSoundVolume:F2}; {_audio.Status}");
			((MelonBase)this).LoggerInstance.Msg($"Visual limits: rays/pulse={_settings.RayCount}; rays/frame={_settings.RaysPerFrame}; max dots={_settings.MaxDots}");
			((MelonBase)this).LoggerInstance.Msg($"Optimize walking/sound echoes={_settings.OptimizeAutomaticEchoes}; caps: {_settings.AutomaticRayLimit} rays/pulse, {_settings.AutomaticFrameBudget} rays/frame, {_settings.AutomaticLifetime:F2}s lifetime");
			((MelonBase)this).LoggerInstance.Msg($"Microphone: {_microphone.Status}; level={_microphone.Level:F4}; threshold={_settings.MicThreshold:F4}");
			((MelonBase)this).LoggerInstance.Msg($"World sources={_world.SourceCount}; threshold={_settings.SoundThreshold:F4}; range={_settings.WorldRange:F0}m");
			((MelonBase)this).LoggerInstance.Msg("Impact audio: " + _worldMonitor.Status);
			((MelonBase)this).LoggerInstance.Msg($"Footsteps: {_locomotion.Status}; world: {_world.Status}; peak={_world.PeakLevel:F4}");
			((MelonBase)this).LoggerInstance.Msg($"Accepted pulses: manual={_counts[0]}, microphone={_counts[1]}, footsteps={_counts[2]}, world={_counts[3]}, voice={_counts[4]}");
		}

		internal void Save()
		{
			try
			{
				_settings.Save();
			}
			catch (Exception ex)
			{
				Warn("Could not save settings: " + ex.Message);
			}
		}

		private void ObserveSound(EchoEvent echo)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if (_active && _settings.Enabled && Finite(echo.Origin))
			{
				_renderer.ObserveSound(echo, _rigRoot);
			}
		}

		private void RegisterWorldPlayback(AudioSource source)
		{
			if (_active && _settings.Enabled && _settings.Mode == ScanMode.EchoLocation && _settings.WorldSoundEnabled && !((Object)(object)source == (Object)null) && ((Behaviour)source).isActiveAndEnabled && !source.mute && !(source.volume <= 0f) && !(source.spatialBlend < 0.5f) && (!source.loop || _settings.IncludeLoopingAudio) && !((Object)(object)_head == (Object)null))
			{
				float unscaledTime = Time.unscaledTime;
				_world.RegisterPlayingSource(source, _objectSources.Capture(unscaledTime, source));
			}
		}

		private void Emit(EchoEvent echo)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			if (_settings.Mode != ScanMode.EchoLocation || (uint)echo.Kind >= (uint)_pending.Length || !_settings.Enabled || !float.IsFinite(echo.Time) || !Finite(echo.Origin))
			{
				return;
			}
			if (echo.Kind != EchoKind.Manual)
			{
				int kind = (int)echo.Kind;
				if (!_hasPending[kind] || echo.Time - _pending[kind].Time > 0.3f || echo.Strength > _pending[kind].Strength)
				{
					_pending[kind] = echo;
				}
				_hasPending[kind] = true;
			}
			else if (!(echo.Time < _nextPulse) && _renderer.Enqueue(echo))
			{
				_nextPulse = echo.Time + _settings.PulseInterval;
				_counts[(int)echo.Kind]++;
			}
		}

		private void FlushInput(float now)
		{
			if (_settings.Mode != ScanMode.EchoLocation || now < _nextPulse)
			{
				return;
			}
			for (int i = 0; i < 4; i++)
			{
				int inputCursor = _inputCursor;
				_inputCursor = _inputCursor % 4 + 1;
				if (_hasPending[inputCursor])
				{
					EchoEvent echoEvent = _pending[inputCursor];
					_hasPending[inputCursor] = false;
					if (!(now - echoEvent.Time > Math.Max(0.35f, _settings.PulseInterval + 0.1f)) && _renderer.Enqueue(echoEvent.WithTime(now)))
					{
						_nextPulse = now + _settings.PulseInterval;
						_counts[inputCursor]++;
						break;
					}
				}
			}
		}

		private void ResetState()
		{
			_active = false;
			_startup.Reset();
			_voiceMeter?.Reset();
			_vrVoiceMeter?.Reset();
			_shortcut.Reset();
			_bulletTrails?.Reset();
			_impactGlow?.Reset();
			_active = false;
			_head = (_rigRoot = null);
			_nextPulse = 0f;
			_clap.Reset();
			Array.Clear(_hasPending, 0, _hasPending.Length);
			try
			{
				_audio?.Stop();
			}
			catch (Exception ex)
			{
				Warn(ex.Message);
			}
			try
			{
				_microphone?.Restart();
			}
			catch (Exception ex2)
			{
				Warn(ex2.Message);
			}
			try
			{
				_world?.Reset();
			}
			catch (Exception ex3)
			{
				Warn(ex3.Message);
			}
			_worldMonitor?.Reset();
			_objectSources?.Reset();
			_locomotion?.Reset();
			try
			{
				_renderer?.Reset();
			}
			catch (Exception ex4)
			{
				Warn(ex4.Message);
			}
		}

		private void Warn(string message)
		{
			float unscaledTime = Time.unscaledTime;
			if (!(unscaledTime < _nextWarning))
			{
				_nextWarning = unscaledTime + 5f;
				((MelonBase)this).LoggerInstance.Warning(message);
			}
		}

		private static bool Finite(Vector3 value)
		{
			//IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			if (float.IsFinite(value.x) && float.IsFinite(value.y))
			{
				return float.IsFinite(value.z);
			}
			return false;
		}
	}
	internal static class EchoMeshSpace
	{
		internal static bool TryGetDrawMatrix(Renderer renderer, SkinnedMeshRenderer? skin, Mesh snapshot, out Matrix4x4 matrix, bool validateBounds = true)
		{
			//IL_0018: 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_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: 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_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: 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_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: 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_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			matrix = (((Object)(object)skin != (Object)null) ? ((Component)skin).transform.localToWorldMatrix : renderer.localToWorldMatrix);
			for (int i = 0; i < 4; i++)
			{
				for (int j = 0; j < 4; j++)
				{
					if (!float.IsFinite(((Matrix4x4)(ref matrix))[i, j]))
					{
						return false;
					}
				}
			}
			if (Math.Abs(((Matrix4x4)(ref matrix))[3, 0]) > 1E-05f || Math.Abs(((Matrix4x4)(ref matrix))[3, 1]) > 1E-05f || Math.Abs(((Matrix4x4)(ref matrix))[3, 2]) > 1E-05f || Math.Abs(((Matrix4x4)(ref matrix))[3, 3] - 1f) > 1E-05f)
			{
				return false;
			}
			Bounds bounds = snapshot.bounds;
			if (!Usable(bounds))
			{
				return false;
			}
			Vector3 extents = ((Bounds)(ref bounds)).extents;
			Vector3 val = ((Matrix4x4)(ref matrix)).MultiplyPoint3x4(((Bounds)(ref bounds)).center);
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(Math.Abs(((Matrix4x4)(ref matrix))[0, 0]) * extents.x + Math.Abs(((Matrix4x4)(ref matrix))[0, 1]) * extents.y + Math.Abs(((Matrix4x4)(ref matrix))[0, 2]) * extents.z, Math.Abs(((Matrix4x4)(ref matrix))[1, 0]) * extents.x + Math.Abs(((Matrix4x4)(ref matrix))[1, 1]) * extents.y + Math.Abs(((Matrix4x4)(ref matrix))[1, 2]) * extents.z, Math.Abs(((Matrix4x4)(ref matrix))[2, 0]) * extents.x + Math.Abs(((Matrix4x4)(ref matrix))[2, 1]) * extents.y + Math.Abs(((Matrix4x4)(ref matrix))[2, 2]) * extents.z);
			if (!Finite(val) || !Finite(val2))
			{
				return false;
			}
			if (!validateBounds)
			{
				return true;
			}
			Bounds bounds2 = renderer.bounds;
			if (!Usable(bounds2))
			{
				return false;
			}
			Vector3 val3 = val - ((Bounds)(ref bounds2)).center;
			Vector3 val4 = ((Bounds)(ref bounds2)).extents * 1.5f + Vector3.one * 0.15f;
			if (Math.Abs(val3.x) + val2.x <= val4.x && Math.Abs(val3.y) + val2.y <= val4.y)
			{
				return Math.Abs(val3.z) + val2.z <= val4.z;
			}
			return false;
		}

		internal static bool SameScale(Vector3 first, Vector3 second)
		{
			//IL_0000: 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_0010: 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_0023: 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_0036: 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 (Finite(first) && Finite(second) && Close(first.x, second.x) && Close(first.y, second.y))
			{
				return Close(first.z, second.z);
			}
			return false;
		}

		private static bool Close(float first, float second)
		{
			return Math.Abs(first - second) <= 0.0001f * Math.Max(0.0001f, Math.Max(Math.Abs(first), Math.Abs(second)));
		}

		private static bool Usable(Bounds bounds)
		{
			//IL_0002: 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_001e: 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_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			if (Finite(((Bounds)(ref bounds)).center) && Finite(((Bounds)(ref bounds)).extents) && ((Bounds)(ref bounds)).extents.x >= 0f && ((Bounds)(ref bounds)).extents.y >= 0f && ((Bounds)(ref bounds)).extents.z >= 0f)
			{
				Vector3 extents = ((Bounds)(ref bounds)).extents;
				return ((Vector3)(ref extents)).sqrMagnitude > 0f;
			}
			return false;
		}

		private static bool Finite(Vector3 value)
		{
			//IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			if (float.IsFinite(value.x) && float.IsFinite(value.y))
			{
				return float.IsFinite(value.z);
			}
			return false;
		}
	}
	internal sealed class EchoRenderer : IDisposable
	{
		private struct Pulse
		{
			internal Vector3 Origin;

			internal Quaternion Rotation;

			internal bool Clap;

			internal bool Lidar;

			internal bool Sonar;

			internal float SweepDuration;

			internal float HeadingX;

			internal float HeadingZ;

			internal bool Automatic;

			internal bool Deduplicate;

			internal EchoKind Kind;

			internal SoundEmitterSurface? SurfaceEmission;

			internal Vector3 ListenerOrigin;

			internal int SurfaceRays;

			internal float Strength;

			internal float Time;

			internal float Range;

			internal float Phase;

			internal int Total;

			internal int Next;

			internal int ShuffleBits;

			internal int ShuffleCursor;
		}

		private struct Dot
		{
			internal Vector3 Position;

			internal Vector3 Normal;

			internal bool Lidar;

			internal bool TrackedObject;

			internal RadarTargetKind RadarKind;

			internal RadarFade RadarFade;

			internal float Birth;

			internal float FadeInStart;

			internal float Lifetime;

			internal float Strength;

			internal bool Indexed;

			internal bool Clap;

			internal SurfaceCell Cell;
		}

		private struct ColliderFlags
		{
			internal Collider Collider;

			internal bool Local;

			internal bool Player;

			internal PlayerTarget? Target;

			internal bool Object;

			internal bool Npc;
		}

		private struct RecentSound
		{
			internal Vector3 Origin;

			internal float Time;

			internal Collider? Owner;

			internal bool Valid;
		}

		private readonly struct SurfaceCell : IEquatable<SurfaceCell>
		{
			private readonly int _collider;

			private readonly int _x;

			private readonly int _y;

			private readonly int _z;

			private readonly int _facing;

			private readonly bool _detail;

			internal SurfaceCell(int collider, Vector3 point, Vector3 normal, float spacing, bool detail)
			{
				//IL_0008: 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_0032: 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_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_008a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0077: Unknown result type (might be due to invalid IL or missing references)
				//IL_009d: Unknown result type (might be due to invalid IL or missing references)
				_collider = collider;
				_x = (int)MathF.Floor(point.x / spacing);
				_y = (int)MathF.Floor(point.y / spacing);
				_z = (int)MathF.Floor(point.z / spacing);
				float num = MathF.Abs(normal.x);
				float num2 = MathF.Abs(normal.y);
				float num3 = MathF.Abs(normal.z);
				_facing = ((num > num2 && num > num3) ? ((!(normal.x >= 0f)) ? 1 : 0) : ((num2 > num3) ? ((normal.y >= 0f) ? 2 : 3) : ((normal.z >= 0f) ? 4 : 5)));
				_detail = detail;
			}

			public bool Equals(SurfaceCell other)
			{
				if (_collider == other._collider && _x == other._x && _y == other._y && _z == other._z && _facing == other._facing)
				{
					return _detail == other._detail;
				}
				return false;
			}

			public override bool Equals(object? obj)
			{
				if (obj is SurfaceCell other)
				{
					return Equals(other);
				}
				return false;
			}

			public override int GetHashCode()
			{
				return HashCode.Combine(_collider, _x, _y, _z, _facing, _detail);
			}
		}

		private readonly RadarScanner _continuous;

		private Transform? _radarRoot;

		private const int QueueLimit = 4;

		private const int HardDotLimit = 65536;

		private const float QueueLifetime = 1.25f;

		private const float WaveSpeed = 45f;

		private const float MaximumWaveTravelTime = 1.25f;

		private const float GoldenAngle = 2.3999631f;

		private const int ShaderAttempts = 6;

		private const int AutomaticRaysPerPulse = 512;

		private const int AutomaticRaysPerFrame = 256;

		private const int EmitterSurfaceRayLimit = 128;

		private const float AutomaticLifetime = 0.85f;

		private const float AutomaticDotSpacing = 0.09f;

		private const int ColliderCacheLimit = 512;

		private static readonly string[] ShaderNames = new string[3] { "Sprites/Default", "Legacy Shaders/Particles/Alpha Blended", "Hidden/Internal-Colored" };

		private readonly Settings _settings;

		private readonly Action<string> _warning;

		private readonly BlackoutView _blackout;

		private readonly PlayerEchoes _players;

		private readonly ScanCoverage _coverage;

		private readonly Pulse[] _pulses = new Pulse[4];

		private readonly Il2CppStructArray<RaycastHit> _hits = new Il2CppStructArray<RaycastHit>(32L);

		private readonly Dictionary<SurfaceCell, int> _surfaceCells = new Dictionary<SurfaceCell, int>();

		private readonly Dictionary<int, ColliderFlags> _colliderFlags = new Dictionary<int, ColliderFlags>(512);

		private readonly RecentSound[] _recentSounds = new RecentSound[8];

		private int _recentSoundCursor;

		private Dot[] _dots = Array.Empty<Dot>();

		private int _dotCount;

		private int _pulseCount;

		private int _pulseCursor;

		private int _overwriteCursor;

		private uint _sequence;

		private Mesh? _mesh;

		private Material? _material;

		private Texture2D? _dotTexture;

		private bool _texturedDots;

		private DotShape _textureShape;

		private double _peakRaysMs;

		private double _peakDotsMs;

		private double _peakPlayersMs;

		private Il2CppStructArray<Vector3>? _vertices;

		private Il2CppStructArray<Color>? _colors;

		private Il2CppStructArray<Vector2>? _uvs;

		private Il2CppStructArray<int>? _indices;

		private int _uploadCapacity;

		private int _shaderAttempts;

		private float _nextShaderAttempt;

		private float _nextSurroundings;

		private bool _disposed;

		private const int CircleSegments = 12;

		private static readonly Vector2[][] ShapeBoundaries = MakeShapeBoundaries();

		internal string PerformanceStatus => $"Scene CPU peaks: rays={_peakRaysMs:F2}ms, dot upload={_peakDotsMs:F2}ms, player pass={_peakPlayersMs:F2}ms; effective ray cap={PulseWorkBudget.RayLimit(_settings.PerformanceLevel, _settings.RaysPerFrame, Time.unscaledDeltaTime)}, dot cap={PulseWorkBudget.DotLimit(_settings.PerformanceLevel, _settings.MaxDots)}; textured dots={_texturedDots}";

		internal bool Ready
		{
			get
			{
				if (!_disposed && (Object)(object)_mesh != (Object)null)
				{
					return (Object)(object)_material != (Object)null;
				}
				return false;
			}
		}

		internal int DotCount => _dotCount;

		internal string VisionStatus => _blackout.Status;

		internal string PlayerStatus => _players.Status;

		private int VerticesPerDot
		{
			get
			{
				if (!_texturedDots)
				{
					return 13;
				}
				return 4;
			}
		}

		private int IndicesPerDot
		{
			get
			{
				if (!_texturedDots)
				{
					return 36;
				}
				return 6;
			}
		}

		internal EchoRenderer(Settings settings, Action<string> warning, ScanCoverage coverage)
		{
			_settings = settings;
			_coverage = coverage;
			_warning = warning;
			_blackout = new BlackoutView(warning);
			_players = new PlayerEchoes(settings, warning, coverage);
			_continuous = new RadarScanner(settings, (Collider collider) => GetColliderFlags(collider, _radarRoot).Local, AddRadarReturn, null, delegate(Collider collider)
			{
				ColliderFlags colliderFlags = GetColliderFlags(collider, _radarRoot);
				return !colliderFlags.Local && !colliderFlags.Player && ((colliderFlags.Npc && _settings.RadarNpcs) || (colliderFlags.Object && _settings.RadarObjects));
			});
		}

		internal void ObserveSound(EchoEvent echo, Transform? localRoot)
		{
			if (_disposed)
			{
				return;
			}
			try
			{
				_players.ObserveSound(echo, localRoot);
			}
			catch (Exception ex)
			{
				_warning("Player sound ownership: " + ex.Message);
			}
		}

		internal bool Enqueue(EchoEvent echo)
		{
			//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)
			return Enqueue(echo, clap: false);
		}

		internal bool EnqueueClap(Vector3 origin, float now)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: 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)
			return Enqueue(new EchoEvent(origin, 1f, EchoKind.Manual, now), clap: true);
		}

		internal void RestartRadar()
		{
			_continuous.Reset();
			_players.Reset();
		}

		internal bool EnqueueLidar(Vector3 origin, Quaternion rotation, float now)
		{
			//IL_0001: 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)
			return Enqueue(new EchoEvent(origin, 1f, EchoKind.Manual, now), clap: false, lidar: true, rotation);
		}

		internal bool EnqueueSonar(Vector3 origin, float now)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: 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)
			return Enqueue(new EchoEvent(origin, 1f, EchoKind.Manual, now), clap: false, lidar: true, default(Quaternion), sonar: true);
		}

		private bool Enqueue(EchoEvent echo, bool clap, bool lidar = false, Quaternion rotation = default(Quaternion), bool sonar = false)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_029f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03af: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0429: Unknown result type (might be due to invalid IL or missing references)
			//IL_042e: Unknown result type (might be due to invalid IL or missing references)
			if (_settings.Mode != ScanMode.EchoLocation && !lidar)
			{
				return false;
			}
			if (_disposed || !Finite(echo.Origin) || !float.IsFinite(echo.Time) || !float.IsFinite(echo.Strength) || echo.Strength <= 0f)
			{
				return false;
			}
			PrunePulses(echo.Time);
			if (echo.Kind == EchoKind.Manual)
			{
				for (int i = 0; i < _pulseCount; i++)
				{
					if (_pulses[i].Kind == EchoKind.Manual)
					{
						return false;
					}
				}
			}
			bool flag = echo.Kind == EchoKind.Ambient;
			bool flag2 = flag || (_settings.OptimizeAutomaticEchoes && !clap && echo.Kind != EchoKind.Manual);
			SoundEmitterSurface soundEmitterSurface = ((echo.Kind == EchoKind.World) ? echo.SurfaceEmission : null);
			if (soundEmitterSurface != null && soundEmitterSurface.Count == 0)
			{
				soundEmitterSurface = null;
			}
			Collider owner = ((soundEmitterSurface != null && soundEmitterSurface.Count > 0) ? soundEmitterSurface.GetCollider(0) : null);
			if (flag2 && !flag && HasRecentNearbySound(echo.Origin, echo.Time, owner))
			{
				return false;
			}
			if (clap && ClapPulseIndex() >= 0)
			{
				return false;
			}
			if (_pulseCount >= 4)
			{
				bool flag3 = soundEmitterSurface != null && soundEmitterSurface.Count > 0;
				if (!clap && !flag3)
				{
					return false;
				}
				int num = -1;
				for (int j = 0; j < _pulseCount; j++)
				{
					if ((clap || (!_pulses[j].Clap && _pulses[j].Kind != EchoKind.Manual && _pulses[j].SurfaceEmission == null)