Decompiled source of Echolocation v1.10.0

Mods/Echolocation.dll

Decompiled a month 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 BoneLib;
using BoneLib.BoneMenu;
using BoneLib.BoneMenu.UI;
using Echolocation;
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 MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(EcholocationMod), "Echolocation", "1.10.0", "Echolocation", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyVersion("0.0.0.0")]
[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)
		{
			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_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: 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_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: 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_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Expected O, but got Unknown
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			if (((Object)(object)_mesh != (Object)null && (Object)(object)_material != (Object)null) || _attempts >= 6 || now < _nextAttempt)
			{
				return;
			}
			_attempts++;
			_nextAttempt = now + 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 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 enum EchoKind
	{
		Manual,
		Microphone,
		Footstep,
		World,
		Voice
	}
	internal readonly struct EchoEvent
	{
		public Vector3 Origin { get; }

		public float Strength { 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)
		{
			//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);
			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);
		}
	}
	public sealed class EcholocationMod : MelonMod
	{
		private Settings _settings;

		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 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 float _gestureStarted = -1f;

		private bool _gestureLatched;

		private readonly DoubleClapGesture _clap = new DoubleClapGesture();

		private readonly SonarClock _sonar = new SonarClock();

		private readonly HandScanInput _leftScan = new HandScanInput();

		private readonly HandScanInput _rightScan = new HandScanInput();

		private readonly HandScanInput _desktopScan = new HandScanInput();

		private int _clapPulseCount;

		private int _sonarPulseCount;

		private int _lidarScanCount;

		public override void OnInitializeMelon()
		{
			_settings = new Settings();
			_renderer = new EchoRenderer(_settings, Warn);
			_microphone = new MicrophoneInput(_settings, Warn);
			_objectSources = new ObjectSoundSources(Warn);
			_world = new WorldSoundInput(_settings, Warn, _objectSources.Capture);
			_locomotion = new LocomotionInput(_settings);
			_menu = new MenuPage(_settings, this, Warn);
			_audio = new PulseAudio(Warn);
			_emit = Emit;
			_observeSound = ObserveSound;
			_worldMonitor = new WorldAudioMonitor(RegisterWorldPlayback, Warn);
			((MelonBase)this).LoggerInstance.Msg("Echolocation 1.10.0 loaded. Sound, rotating Sonar and hand LiDAR in BoneMenu; F6 toggle; F5 scan.");
			((MelonBase)this).LoggerInstance.Msg("Visuals are local. Mic loudness is measured in memory only; no audio is saved or sent by this mod.");
			Save();
		}

		public override void OnUpdate()
		{
			//IL_0188: 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_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Unknown result type (might be due to invalid IL or missing references)
			if (_settings == null)
			{
				return;
			}
			_menu.EnsureBuilt();
			ReadVisionGesture();
			if (_settings.DesktopHotkeys)
			{
				if (Input.GetKeyDown((KeyCode)287))
				{
					SetEnabled(!_settings.Enabled);
				}
				if (_settings.Mode != ScanMode.Lidar && 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)
			{
				_clap.Reset();
				if (_active)
				{
					ResetState();
				}
				return;
			}
			if (_active && ((Object)(object)_head != (Object)(object)val || (Object)(object)_rigRoot != (Object)(object)val2))
			{
				ResetState();
			}
			_head = val;
			_rigRoot = val2;
			_active = true;
			float unscaledTime = Time.unscaledTime;
			ReadClapGesture(unscaledTime, val);
			try
			{
				_microphone.Tick(unscaledTime, val.position, _emit, _observeSound);
			}
			catch (Exception ex2)
			{
				Warn("Microphone/voice input: " + ex2.Message);
			}
			try
			{
				_locomotion.Tick(unscaledTime, val, val2, _emit);
			}
			catch (Exception ex3)
			{
				Warn("Footstep input: " + ex3.Message);
			}
			try
			{
				_renderer.TickRemoteFootsteps(unscaledTime, val.position, val2, _emit, _observeSound);
			}
			catch (Exception ex4)
			{
				Warn("Remote footstep input: " + ex4.Message);
			}
			try
			{
				if (_settings.WorldSoundEnabled)
				{
					_worldMonitor.Tick(unscaledTime);
				}
				else
				{
					_worldMonitor.Reset();
				}
			}
			catch (Exception ex5)
			{
				Warn("World playback monitoring: " + ex5.Message);
			}
			try
			{
				_world.Tick(unscaledTime, val.position, _emit, _observeSound);
			}
			catch (Exception ex6)
			{
				Warn("World sound input: " + ex6.Message);
			}
			if (_settings.Mode == ScanMode.Sound)
			{
				FlushInput(unscaledTime);
			}
			try
			{
				bool flag = _renderer.Ready && CanAutoScan();
				bool flag2 = _settings.Mode == ScanMode.Sonar && flag;
				if (flag2)
				{
					_renderer.UpdateSonar(val.position, unscaledTime, 0.5f);
				}
				else
				{
					_renderer.StopSonar();
				}
				if (_sonar.TryPulse(unscaledTime, flag2))
				{
					_sonarPulseCount++;
					if (_settings.PulseSoundEnabled)
					{
						_audio.PlayPulse(_settings.PulseSoundVolume);
					}
				}
				ReadLidar(unscaledTime, val, _settings.Mode == ScanMode.Lidar && flag);
			}
			catch (Exception ex7)
			{
				_sonar.Reset();
				_renderer.StopSonar();
				ResetHandScans();
				Warn("Scan input: " + ex7.Message);
			}
		}

		public override void OnLateUpdate()
		{
			if (!_active || !_settings.Enabled || (Object)(object)_head == (Object)null)
			{
				return;
			}
			try
			{
				_renderer.Tick(Time.unscaledTime, _head, _rigRoot);
			}
			catch (Exception ex)
			{
				Warn("Surface renderer: " + ex.Message);
			}
		}

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

		public override void OnDeinitializeMelon()
		{
			if (_settings != null)
			{
				ResetState();
				try
				{
					_worldMonitor.Dispose();
				}
				catch (Exception ex)
				{
					Warn(ex.Message);
				}
				try
				{
					_microphone.Dispose();
				}
				catch (Exception ex2)
				{
					Warn(ex2.Message);
				}
				try
				{
					_world.Dispose();
				}
				catch (Exception ex3)
				{
					Warn(ex3.Message);
				}
				try
				{
					_renderer.Dispose();
				}
				catch (Exception ex4)
				{
					Warn(ex4.Message);
				}
				try
				{
					_audio.Dispose();
				}
				catch (Exception ex5)
				{
					Warn(ex5.Message);
				}
				Save();
			}
		}

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

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

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

		private static bool CanAutoScan()
		{
			OpenControllerRig controllerRig = Player.ControllerRig;
			if (((Object)(object)controllerRig != (Object)null && ((ControllerRig)controllerRig).IsPaused) || Time.timeScale <= 0f)
			{
				return false;
			}
			UIRig uIRig = Player.UIRig;
			GUIMenu instance = GUIMenu.Instance;
			if (!((Object)(object)uIRig != (Object)null) || !((Object)(object)uIRig.popUpMenu != (Object)null) || !uIRig.popUpMenu.isActive)
			{
				if ((Object)(object)instance != (Object)null)
				{
					return !((Component)instance).gameObject.activeInHierarchy;
				}
				return true;
			}
			return false;
		}

		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()
		{
			_audio.PlayPulse(_settings.PulseSoundVolume);
		}

		private void ReadClapGesture(float now, Transform head)
		{
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: 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)
			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);
			}
		}

		private void ReadVisionGesture()
		{
			if (_settings.Mode == ScanMode.Lidar)
			{
				_gestureStarted = -1f;
				_gestureLatched = false;
				return;
			}
			bool flag = false;
			try
			{
				flag = Player.HandsExist && Player.LeftHand._indexButton && Player.RightHand._indexButton && !Player.LeftHand.HasAttachedObject() && !Player.RightHand.HasAttachedObject();
			}
			catch (Exception)
			{
			}
			if (!flag)
			{
				_gestureStarted = -1f;
				_gestureLatched = false;
			}
			else if (!_gestureLatched)
			{
				float unscaledTime = Time.unscaledTime;
				if (_gestureStarted < 0f)
				{
					_gestureStarted = unscaledTime;
				}
				if (!(unscaledTime - _gestureStarted < 1.5f))
				{
					_gestureLatched = true;
					SetBlackout(!_settings.Blackout);
				}
			}
		}

		internal void ManualPulse()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (!_settings.Enabled)
			{
				return;
			}
			try
			{
				Transform head = Player.Head;
				if ((Object)(object)head != (Object)null)
				{
					Emit(new EchoEvent(head.position, 1f, EchoKind.Manual, Time.unscaledTime));
				}
			}
			catch (Exception ex)
			{
				Warn("Manual pulse needs a loaded player rig: " + ex.Message);
			}
		}

		private void ReadLidar(float now, Transform head, bool available)
		{
			if (!available)
			{
				ResetHandScans();
				return;
			}
			BaseController leftController = Player.LeftController;
			BaseController rightController = Player.RightController;
			XRApi xr = MarrowGame.xr;
			XRController val = ((xr != null) ? xr.LeftController : null);
			XRApi xr2 = MarrowGame.xr;
			XRController val2 = ((xr2 != null) ? xr2.RightController : null);
			bool handsExist = Player.HandsExist;
			bool flag = handsExist && (Object)(object)leftController != (Object)null && ((Behaviour)leftController).isActiveAndEnabled && val != null && ((XRDevice)val).IsConnected && !Player.LeftHand.HasAttachedObject();
			bool flag2 = handsExist && (Object)(object)rightController != (Object)null && ((Behaviour)rightController).isActiveAndEnabled && val2 != null && ((XRDevice)val2).IsConnected && !Player.RightHand.HasAttachedObject();
			if (_leftScan.TryScan(now, flag, flag && (val.TriggerButton || val.Trigger >= 0.65f)))
			{
				SendLidar(((Component)leftController).transform, now);
			}
			if (_rightScan.TryScan(now, flag2, flag2 && (val2.TriggerButton || val2.Trigger >= 0.65f)))
			{
				SendLidar(((Component)rightController).transform, now);
			}
			if (_desktopScan.TryScan(now, _settings.DesktopHotkeys, _settings.DesktopHotkeys && Input.GetKey((KeyCode)286)))
			{
				SendLidar(head, now);
			}
		}

		private void SendLidar(Transform source, float now)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if (_renderer.EnqueueLidar(source.position, source.rotation, now))
			{
				_lidarScanCount++;
			}
		}

		private void ResetHandScans()
		{
			_leftScan.Reset();
			_rightScan.Reset();
			_desktopScan.Reset();
		}

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

		internal void Diagnostics()
		{
			((MelonBase)this).LoggerInstance.Msg($"Enabled={_settings.Enabled}; rig={_active}; renderer={_renderer.Ready}; dots={_renderer.DotCount}");
			((MelonBase)this).LoggerInstance.Msg($"Scan mode={_settings.Mode}; sonar turn={0.5f:F1}s; sonar turns={_sonarPulseCount}; LiDAR scans={_lidarScanCount}");
			((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($"Faint nearby players={_settings.ProximitySilhouettes}; proximity radius={_settings.ProximityRange:F2}m; reveal range={_settings.Range:F0}m; dot brightness={_settings.DotBrightness:F2}");
			((MelonBase)this).LoggerInstance.Msg($"Double clap enabled={_settings.DoubleClapEnabled}; contact distance={_settings.ClapContactDistance:F2}m; 360 pulses={_clapPulseCount}");
			((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}; when enabled: 512 rays/pulse, 256 rays/frame, 0.85s dot lifetime caps");
			((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($"Remote footstep sensitivity={_settings.RemoteFootstepSensitivity:F1}x; effective threshold={_settings.SoundThreshold / _settings.RemoteFootstepSensitivity:F5}; walking enabled={_settings.FootstepsEnabled}");
			((MelonBase)this).LoggerInstance.Msg($"Remote walking without audio={_settings.RemoteWalkingDetection}");
			((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.WorldSoundEnabled && !((Object)(object)source == (Object)null) && ((Behaviour)source).isActiveAndEnabled && !source.mute && !(source.volume <= 0f) && WorldSoundInput.IsSpatialSource(source) && (!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_001d: Unknown result type (might be due to invalid IL or missing references)
			if (!_settings.Enabled || !float.IsFinite(echo.Time) || !Finite(echo.Origin))
			{
				return;
			}
			if (echo.Kind == EchoKind.World && echo.SurfaceEmission != null && echo.SurfaceEmission.Count > 0)
			{
				if (_renderer.Enqueue(echo))
				{
					_counts[(int)echo.Kind]++;
				}
			}
			else
			{
				if (_settings.Mode != ScanMode.Sound && echo.Kind != EchoKind.Manual)
				{
					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 + 0.12f;
					_counts[(int)echo.Kind]++;
				}
			}
		}

		private void FlushInput(float now)
		{
			if (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 > 0.35f) && _renderer.Enqueue(echoEvent.WithTime(now)))
					{
						_nextPulse = now + 0.12f;
						_counts[inputCursor]++;
						break;
					}
				}
			}
		}

		private void ResetState()
		{
			_active = false;
			_head = (_rigRoot = null);
			_nextPulse = 0f;
			_gestureStarted = -1f;
			_gestureLatched = false;
			_clap.Reset();
			_sonar.Reset();
			ResetHandScans();
			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, Bounds? trackedBounds = null)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: 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_0045: 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_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: 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_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: 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_00e2: 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_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: 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_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: 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_00bb: 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_00c1: 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_00cb: 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_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: 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)
			matrix = (((Object)(object)skin != (Object)null) ? Matrix4x4.TRS(((Component)skin).transform.position, ((Component)skin).transform.rotation, Vector3.one) : renderer.localToWorldMatrix);
			Bounds bounds = snapshot.bounds;
			Bounds bounds2 = renderer.bounds;
			if (!Usable(bounds) || !Usable(bounds2))
			{
				return false;
			}
			bool flag = FitsSource(matrix, bounds, bounds2);
			if ((Object)(object)skin == (Object)null)
			{
				return flag;
			}
			Matrix4x4 localToWorldMatrix = ((Component)skin).transform.localToWorldMatrix;
			if (!FitsSource(localToWorldMatrix, bounds, bounds2))
			{
				return flag;
			}
			if (!flag)
			{
				goto IL_00e1;
			}
			if (trackedBounds.HasValue)
			{
				Bounds valueOrDefault = trackedBounds.GetValueOrDefault();
				if (Usable(valueOrDefault) && FitsSource(localToWorldMatrix, bounds, valueOrDefault) && FitError(localToWorldMatrix, bounds, valueOrDefault) < FitError(matrix, bounds, valueOrDefault) && FitError(localToWorldMatrix, bounds, bounds2) < FitError(matrix, bounds, bounds2))
				{
					goto IL_00e1;
				}
			}
			goto IL_00e8;
			IL_00e1:
			matrix = localToWorldMatrix;
			goto IL_00e8;
			IL_00e8:
			return true;
		}

		private static float FitError(Matrix4x4 matrix, Bounds local, Bounds source)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: 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_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			WorldBounds(matrix, local, out var center, out var half);
			Vector3 val = center - ((Bounds)(ref source)).center;
			Vector3 val2 = half - ((Bounds)(ref source)).extents;
			return (Math.Abs(val.x) + Math.Abs(val2.x)) / Math.Max(0.05f, ((Bounds)(ref source)).extents.x) + (Math.Abs(val.y) + Math.Abs(val2.y)) / Math.Max(0.05f, ((Bounds)(ref source)).extents.y) + (Math.Abs(val.z) + Math.Abs(val2.z)) / Math.Max(0.05f, ((Bounds)(ref source)).extents.z);
		}

		private static bool FitsSource(Matrix4x4 matrix, Bounds local, Bounds source)
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: 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_00ad: 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)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: 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_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: 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_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			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;
			}
			WorldBounds(matrix, local, out var center, out var half);
			if (!Finite(center) || !Finite(half))
			{
				return false;
			}
			Vector3 val = center - ((Bounds)(ref source)).center;
			Vector3 val2 = ((Bounds)(ref source)).extents * 1.5f + Vector3.one * 0.15f;
			if (Math.Abs(val.x) + half.x <= val2.x && Math.Abs(val.y) + half.y <= val2.y)
			{
				return Math.Abs(val.z) + half.z <= val2.z;
			}
			return false;
		}

		private static void WorldBounds(Matrix4x4 matrix, Bounds local, out Vector3 center, out Vector3 half)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: 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_00e5: Unknown result type (might be due to invalid IL or missing references)
			Vector3 extents = ((Bounds)(ref local)).extents;
			center = ((Matrix4x4)(ref matrix)).MultiplyPoint3x4(((Bounds)(ref local)).center);
			half = new Vector3(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);
		}

		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 Sonar;

			internal bool Lidar;

			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 float Sweep;

			internal int SampleOffset;

			internal int Total;

			internal int Next;

			internal int ShuffleBits;

			internal int ShuffleCursor;
		}

		private struct Dot
		{
			internal Vector3 Position;

			internal Color Color;

			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;
		}

		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.z >= 0f) ? 4 : 5) : ((normal.y >= 0f) ? 2 : 3)));
				_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 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 SonarRaysPerTurn = 2048;

		private const int LidarRaysPerScan = 128;

		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 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 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 bool _disposed;

		private bool _sonarActive;

		private float _sonarTime;

		private double _sonarTurn;

		private double _sonarRemainder;

		private int _sonarSample;

		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;

		internal EchoRenderer(Settings settings, Action<string> warning)
		{
			_settings = settings;
			_warning = warning;
			_blackout = new BlackoutView(warning);
			_players = new PlayerEchoes(settings, warning);
		}

		internal void TickRemoteFootsteps(float now, Vector3 head, Transform? rigRoot, Action<EchoEvent> emit, Action<EchoEvent> observeSound)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (!_disposed)
			{
				_players.TickFootsteps(now, head, rigRoot, emit, observeSound);
			}
		}

		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)
		{
			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)
			return Enqueue(new EchoEvent(origin, 1f, EchoKind.Manual, now), clap: true);
		}

		internal void UpdateSonar(Vector3 origin, float now, float secondsPerTurn)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			if (_disposed || !Finite(origin) || !float.IsFinite(now) || now < 0f || !float.IsFinite(secondsPerTurn) || secondsPerTurn <= 0f)
			{
				StopSonar();
				return;
			}
			if (!_sonarActive || now < _sonarTime)
			{
				StopSonar();
				_sonarActive = true;
				_sonarTime = now;
				return;
			}
			double num = (double)now - (double)_sonarTime;
			if (num <= 0.0)
			{
				return;
			}
			_sonarTime = now;
			double num2 = num / (double)Math.Clamp(secondsPerTurn, 0.25f, 10f);
			double num3 = _sonarTurn;
			_sonarTurn = (_sonarTurn + num2) % 1.0;
			if (num > 0.25 || num2 > 0.25)
			{
				num2 = 1.0 / 64.0;
				num3 = _sonarTurn - num2;
				_sonarRemainder = 0.0;
			}
			double num4 = (double)Math.Clamp(_settings.RayCount, 32, 2048) * num2 + _sonarRemainder;
			int num5 = (int)Math.Floor(num4 + 1E-06);
			_sonarRemainder = Math.Max(0.0, num4 - (double)num5);
			for (int num6 = _pulseCount - 1; num6 >= 0; num6--)
			{
				if (_pulses[num6].Sonar)
				{
					RemovePulse(num6);
				}
			}
			if (num5 != 0)
			{
				Pulse pulse = ScanPulse(origin, now, Math.Min(num5, 256));
				pulse.Sonar = true;
				pulse.SampleOffset = _sonarSample;
				_sonarSample = (_sonarSample + num5) % 65536;
				pulse.Phase = (float)(num3 * Math.PI * 2.0);
				pulse.Sweep = (float)(num2 * Math.PI * 2.0);
				QueueScan(pulse);
			}
		}

		internal void StopSonar()
		{
			_sonarActive = false;
			_sonarTime = 0f;
			_sonarTurn = 0.0;
			_sonarRemainder = 0.0;
			_sonarSample = 0;
			for (int num = _pulseCount - 1; num >= 0; num--)
			{
				if (_pulses[num].Sonar)
				{
					RemovePulse(num);
				}
			}
		}

		internal bool EnqueueLidar(Vector3 origin, Quaternion rotation, float now)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: 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_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			float num = rotation.x * rotation.x + rotation.y * rotation.y + rotation.z * rotation.z + rotation.w * rotation.w;
			if (_disposed || !Finite(origin) || !float.IsFinite(now) || now < 0f || !float.IsFinite(num) || num < 0.0001f)
			{
				return false;
			}
			float num2 = 1f / Mathf.Sqrt(num);
			Pulse pulse = ScanPulse(origin, now, Math.Clamp(_settings.RayCount, 32, 128));
			pulse.Lidar = true;
			pulse.Rotation = new Quaternion(rotation.x * num2, rotation.y * num2, rotation.z * num2, rotation.w * num2);
			return QueueScan(pulse);
		}

		private Pulse ScanPulse(Vector3 origin, float now, int total)
		{
			//IL_000a: 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)
			return new Pulse
			{
				Origin = origin,
				Time = now,
				Strength = 1f,
				Range = (float.IsFinite(_settings.Range) ? Mathf.Clamp(_settings.Range, 2f, 3000f) : 3000f),
				Kind = EchoKind.Manual,
				Total = total,
				Phase = (float)(++_sequence % 65536) * 2.3999631f,
				Automatic = true,
				Deduplicate = true
			};
		}

		private bool QueueScan(Pulse pulse)
		{
			PrunePulses(pulse.Time);
			int num = 0;
			int num2 = -1;
			for (int i = 0; i < _pulseCount; i++)
			{
				if (_pulses[i].Lidar)
				{
					num++;
					if (num2 < 0 || _pulses[i].Time < _pulses[num2].Time)
					{
						num2 = i;
					}
				}
			}
			if (pulse.Lidar && num >= 2)
			{
				RemovePulse(num2);
			}
			if (_pulseCount >= 4)
			{
				int num3 = -1;
				for (int j = 0; j < _pulseCount; j++)
				{
					ref Pulse reference = ref _pulses[j];
					if (!reference.Clap && !reference.Lidar && reference.SurfaceEmission == null && (reference.Kind != EchoKind.Manual || reference.Sonar) && (num3 < 0 || reference.Time < _pulses[num3].Time))
					{
						num3 = j;
					}
				}
				if (num3 < 0)
				{
					return false;
				}
				RemovePulse(num3);
			}
			_pulses[_pulseCount++] = pulse;
			return true;
		}

		private bool Enqueue(EchoEvent echo, bool clap)
		{
			//IL_000a: 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_02c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0404: Unknown result type (might be due to invalid IL or missing references)
			if (_disposed || !Finite(echo.Origin) || !float.IsFinite(echo.Time) || !float.IsFinite(echo.Strength) || echo.Strength <= 0f)
			{
				return false;
			}
			PrunePulses(echo.Time);
			bool 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 (flag && HasRecentNearbySound(echo.Origin, echo.Time, owner))
			{
				return false;
			}
			if (clap && ClapPulseIndex() >= 0)
			{
				return false;
			}
			if (_pulseCount >= 4 && (clap || echo.Kind == EchoKind.Manual || soundEmitterSurface != null))
			{
				for (int i = 0; i < _pulseCount; i++)
				{
					if (_pulses[i].Sonar || (_pulses[i].Lidar && (clap || echo.Kind == EchoKind.Manual)))
					{
						RemovePulse(i);
						break;
					}
				}
			}
			if (_pulseCount >= 4)
			{
				bool flag2 = soundEmitterSurface != null && soundEmitterSurface.Count > 0;
				if (!clap && !flag2)
				{
					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)) && (num < 0 || _pulses[j].Time < _pulses[num].Time))
					{
						num = j;
					}
				}
				if (num < 0)
				{
					return false;
				}
				RemovePulse(num);
			}
			float num2 = Mathf.Clamp01(echo.Strength);
			int num3 = Mathf.Clamp(_settings.RayCount, 32, 16384);
			int num4 = (clap ? Math.Min(Math.Clamp(num3 * 3, 256, 32768), Math.Clamp(_settings.RaysPerFrame, 8, 4096) * 45) : Mathf.Max(16, Mathf.RoundToInt((float)num3 * Mathf.Lerp(0.55f, 1f, num2))));
			if (flag)
			{
				num4 = Math.Min(num4, 512);
			}
			int k = 0;
			if (clap)
			{
				for (; 1 << k < num4; k++)
				{
				}
			}
			_pulses[_pulseCount++] = new Pulse
			{
				Origin = echo.Origin,
				Strength = num2,
				Time = echo.Time,
				Kind = echo.Kind,
				SurfaceEmission = soundEmitterSurface,
				SurfaceRays = ((soundEmitterSurface != null && soundEmitterSurface.Count > 0) ? Math.Min(num4 / 4, 128) : 0),
				Range = (float.IsFinite(_settings.Range) ? Mathf.Clamp(_settings.Range, 2f, 3000f) : 3000f) * Mathf.Lerp(0.4f, 1f, num2),
				Total = num4,
				Phase = (float)(++_sequence % 65536) * 2.3999631f,
				Clap = clap,
				Automatic = flag,
				Deduplicate = _settings.OptimizeAutomaticEchoes,
				ShuffleBits = k
			};
			if (flag)
			{
				_recentSounds[_recentSoundCursor++ % _recentSounds.Length] = new RecentSound
				{
					Origin = echo.Origin,
					Time = echo.Time,
					Owner = owner,
					Valid = true
				};
			}
			if (_recentSoundCursor >= _recentSounds.Length)
			{
				_recentSoundCursor = 0;
			}
			return true;
		}

		internal void Tick(float now, Transform head, Transform? rigRoot)
		{
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: 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_013a: Unknown result type (might be due to invalid IL or missing references)
			if (_disposed || (Object)(object)head == (Object)null || !float.IsFinite(now))
			{
				return;
			}
			_players.PrepareTargets(now, rigRoot);
			EnsureAssets(now);
			PrunePulses(now);
			if (!Ready)
			{
				return;
			}
			_blackout.Tick(now, _settings.Blackout);
			_material.renderQueue = (_blackout.Active ? 4999 : 3001);
			EnsureCapacity(Mathf.Clamp(_settings.MaxDots, 64, 65536));
			ExpireDots(now);
			_colliderFlags.Clear();
			int val = Mathf.Clamp(_settings.RaysPerFrame, 8, 4096);
			int num = Math.Min(val, 256);
			while (val-- > 0 && _pulseCount > 0)
			{
				int num2 = NextPulseIndex(num > 0);
				if (num2 < 0)
				{
					break;
				}
				_pulseCursor = num2;
				ref Pulse reference = ref _pulses[_pulseCursor];
				if (reference.Automatic)
				{
					num--;
				}
				if (reference.Next == 0 && !reference.Clap && !reference.Sonar && !reference.Lidar)
				{
					reference.Rotation = head.rotation;
					reference.ListenerOrigin = head.position;
				}
				CastReturn(ref reference, now, rigRoot);
				if (reference.Next >= reference.Total)
				{
					RemovePulse(_pulseCursor);
				}
				else
				{
					_pulseCursor++;
				}
			}
			Draw(now, head);
			try
			{
				_players.Tick(now, head, rigRoot);
			}
			catch (Exception ex)
			{
				_warning("Player visibility: " + ex.Message);
			}
		}

		internal void Reset()
		{
			_blackout.Reset();
			_players.Reset();
			_dotCount = 0;
			_pulseCount = 0;
			StopSonar();
			_pulseCursor = 0;
			_overwriteCursor = 0;
			_surfaceCells.Clear();
			_colliderFlags.Clear();
			Array.Clear(_recentSounds, 0, _recentSounds.Length);
			_recentSoundCursor = 0;
			_shaderAttempts = 0;
			_nextShaderAttempt = 0f;
			if ((Object)(object)_mesh != (Object)null)
			{
				_mesh.Clear();
			}
		}

		public void Dispose()
		{
			if (!_disposed)
			{
				_disposed = true;
				_blackout.Dispose();
				_players.Dispose();
				_pulseCount = 0;
				_dotCount = 0;
				_surfaceCells.Clear();
				_colliderFlags.Clear();
				DestroyAssets();
				_dots = Array.Empty<Dot>();
				_vertices = null;
				_colors = null;
				_uvs = null;
				_indices = null;
				_uploadCapacity = 0;
			}
		}

		private void CastReturn(ref Pulse pulse, float now, Transform? rigRoot)
		{
			//IL_015b: 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)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0282: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			int num = pulse.Next++;
			if (num % 4 == 0 && num / 4 < pulse.SurfaceRays && TryEmitterRay(pulse, num / 4, rigRoot, out var direction, out var range))
			{
				if (FindReturn(pulse.ListenerOrigin, direction, range, rigRoot, null, out var selected) && pulse.SurfaceEmission.IsOwnCollider(((RaycastHit)(ref selected)).collider))
				{
					AddReturn(ref pulse, selected, ((RaycastHit)(ref selected)).distance, now);
				}
				return;
			}
			float num2 = ((float)num + 0.5f) / (float)pulse.Total;
			float num3 = (float)num * 2.3999631f + pulse.Phase;
			Vector3 direction2 = default(Vector3);
			if (pulse.Sonar)
			{
				float num4 = 1f - 2f * (float)(((double)(num + pulse.SampleOffset) * 0.61803398875 + 0.5) % 1.0);
				float num5 = Mathf.Sqrt(Mathf.Max(0f, 1f - num4 * num4));
				float num6 = pulse.Phase + pulse.Sweep * num2;
				((Vector3)(ref direction2))..ctor(num5 * Mathf.Sin(num6), num4, num5 * Mathf.Cos(num6));
			}
			else if (pulse.Lidar)
			{
				float num7 = Mathf.Lerp(1f, 0.819152f, num2);
				float num8 = Mathf.Sqrt(Mathf.Max(0f, 1f - num7 * num7));
				direction2 = pulse.Rotation * new Vector3(num8 * Mathf.Cos(num3), num8 * Mathf.Sin(num3), num7);
			}
			else if (pulse.Clap)
			{
				int num9;
				do
				{
					num9 = ReverseLowBits(pulse.ShuffleCursor++, pulse.ShuffleBits);
				}
				while (num9 >= pulse.Total);
				float num10 = 1f - 2f * (((float)num9 + 0.5f) / (float)pulse.Total);
				float num11 = Mathf.Sqrt(Mathf.Max(0f, 1f - num10 * num10));
				float num12 = (float)num9 * 2.3999631f + pulse.Phase;
				((Vector3)(ref direction2))..ctor(num11 * Mathf.Cos(num12), num10, num11 * Mathf.Sin(num12));
			}
			else if (num % 3 == 0)
			{
				float num13 = Mathf.Lerp(1f, 0.25f, num2);
				float num14 = Mathf.Sqrt(Mathf.Max(0f, 1f - num13 * num13));
				direction2 = pulse.Rotation * new Vector3(num14 * Mathf.Cos(num3), num14 * Mathf.Sin(num3), num13);
			}
			else
			{
				float num15 = 1f - 2f * num2;
				float num16 = Mathf.Sqrt(Mathf.Max(0f, 1f - num15 * num15));
				((Vector3)(ref direction2))..ctor(num16 * Mathf.Cos(num3), num15, num16 * Mathf.Sin(num3));
			}
			if (FindReturn(pulse.Origin, direction2, pulse.Range, rigRoot, pulse.SurfaceEmission, out var selected2))
			{
				AddReturn(ref pulse, selected2, ((RaycastHit)(ref selected2)).distance, now);
			}
		}

		private bool TryEmitterRay(Pulse pulse, int sample, Transform? rigRoot, out Vector3 direction, out float range)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: 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_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: 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_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: 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_01c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: 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_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: 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_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_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			direction = default(Vector3);
			range = 0f;
			SoundEmitterSurface? surfaceEmission = pulse.SurfaceEmission;
			int count = surfaceEmission.Count;
			int index = ((count > pulse.SurfaceRays) ? (sample * count / pulse.SurfaceRays) : (sample % count));
			Collider collider = surfaceEmission.GetCollider(index);
			if ((Object)(object)collider == (Object)null)
			{
				return false;
			}
			ColliderFlags colliderFlags = GetColliderFlags(collider, rigRoot);
			if (colliderFlags.Local || colliderFlags.Player)
			{
				return false;
			}
			Bounds bounds = collider.bounds;
			Vector3 center = ((Bounds)(ref bounds)).center;
			Vector3 extents = ((Bounds)(ref bounds)).extents;
			if (!Finite(center) || !Finite(extents) || ((Vector3)(ref extents)).sqrMagnitude < 1E-06f || ((Bounds)(ref bounds)).Contains(pulse.ListenerOrigin) || !Finite(pulse.ListenerOrigin) || Vector3.Distance(pulse.ListenerOrigin, pulse.Origin) > _settings.WorldRange)
			{
				return false;
			}
			Vector3 val = pulse.ListenerOrigin - center;
			int num = sample / count;
			float num2 = ((num == 0) ? 0f : (0.85f * Mathf.Sqrt((float)num * 0.618034f % 1f)));
			float num3 = (float)num * 2.3999631f + pulse.Phase;
			float num4 = num2 * Mathf.Cos(num3);
			float num5 = num2 * Mathf.Sin(num3);
			float num6 = Mathf.Abs(val.x);
			float num7 = Mathf.Abs(val.y);
			float num8 = Mathf.Abs(val.z);
			Vector3 val2 = ((num6 > num7 && num6 > num8) ? new Vector3((val.x >= 0f) ? extents.x : (0f - extents.x), num4 * extents.y, num5 * extents.z) : ((num7 > num8) ? new Vector3(num4 * extents.x, (val.y >= 0f) ? extents.y : (0f - extents.y), num5 * extents.z) : new Vector3(num4 * extents.x, num5 * extents.y, (val.z >= 0f) ? extents.z : (0f - extents.z))));
			Vector3 val3 = center + val2 - pulse.ListenerOrigin;
			float magnitude = ((Vector3)(ref val3)).magnitude;
			if (!float.IsFinite(magnitude) || magnitude < 0.001f)
			{
				return false;
			}
			direction = val3 / magnitude;
			range = Math.Min(magnitude + ((Vector3)(ref extents)).magnitude * 2f + 0.02f, _settings.WorldRange + ((Vector3)(ref extents)).magnitude * 2f);
			if (float.IsFinite(range))
			{
				return range > 0f;
			}
			return false;
		}

		private bool FindReturn(Vector3 origin, Vector3 direction, float range, Transform? rigRoot, SoundEmitterSurface? ignoredOwner, out RaycastHit selected)
		{
			//IL_0002: 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_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: 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)
			selected = default(RaycastHit);
			int num = Physics.RaycastNonAlloc(origin, direction, _hits, range, -5, (QueryTriggerInteraction)1);
			if (num == 0 || num >= ((Il2CppArrayBase<RaycastHit>)(object)_hits).Length)
			{
				return false;
			}
			float num2 = float.PositiveInfinity;
			bool flag = false;
			for (int i = 0; i < num; i++)
			{
				RaycastHit val = ((Il2CppArrayBase<RaycastHit>)(object)_hits)[i];
				Collider collider = ((RaycastHit)(ref val)).collider;
				if (!((Object)(object)collider == (Object)null) && !(((RaycastHit)(ref val)).distance >= num2))
				{
					ColliderFlags colliderFlags = GetColliderFlags(collider, rigRoot);
					if (!colliderFlags.Local && (colliderFlags.Player || ignoredOwner == null || !ignoredOwner.IsOwnCollider(collider)))
					{
						num2 = ((RaycastHit)(ref val)).distance;
						selected = val;
						flag = true;
					}
				}
			}
			if (!flag)
			{
				return false;
			}
			if (GetColliderFlags(((RaycastHit)(ref selected)).collider, rigRoot).Player)
			{
				return false;
			}
			return true;
		}

		private void AddReturn(ref Pulse pulse, RaycastHit selected, float nearest, float now)
		{
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: 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_02ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Unknown result type (might be due to invalid IL or missing references)
			//IL_030b: Unknown result type (might be due to invalid IL or missing references)
			//IL_032b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: 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_01ed: Unknown result type (might be due to invalid IL or missing references)
			float num = Mathf.Max(45f, Mathf.Max(pulse.Range, nearest) / 1.25f);
			bool flag = pulse.Sonar || pulse.Lidar;
			float num2 = (flag ? now : ((pulse.Clap ? now : pulse.Time) + nearest / num));
			float num3 = Mathf.Clamp(_settings.DotLifetime, 0.15f, 8f);
			if (pulse.Clap)
			{
				num3 = Mathf.Max(2.5f, num3);
			}
			if (pulse.Automatic)
			{
				num3 = Math.Min(num3, 0.85f);
			}
			if (pulse.Sonar)
			{
				num3 = Math.Min(num3, 0.35f);
			}
			if (now >= num2 + num3)
			{
				return;
			}
			SurfaceCell surfaceCell = default(SurfaceCell);
			if (pulse.Deduplicate)
			{
				if (!Finite(((RaycastHit)(ref selected)).point) || !Finite(((RaycastHit)(ref selected)).normal))
				{
					return;
				}
				surfaceCell = new SurfaceCell(((Object)((RaycastHit)(ref selected)).collider).GetInstanceID(), ((RaycastHit)(ref selected)).point, ((RaycastHit)(ref selected)).normal, pulse.Automatic ? 0.09f : 0.04f, !pulse.Automatic);
				if (_surfaceCells.TryGetValue(surfaceCell, out var value))
				{
					ref Dot reference = ref _dots[value];
					if (!reference.Clap || pulse.Clap)
					{
						reference.Birth = ((reference.Birth <= now) ? Math.Min(num2, now) : Math.Min(reference.Birth, num2));
						if (flag)
						{
							reference.FadeInStart = Math.Min(reference.FadeInStart, now - 0.025f);
						}
						reference.Lifetime = num3;
						reference.Strength = Math.Max(reference.Strength, ReturnStrength(pulse, nearest));
						reference.Color = (Color)(pulse.Clap ? new Color(0.65f, 0.98f, 1f, 1f) : ColorFor(pulse.Kind));
						reference.Clap = pulse.Clap;
					}
					return;
				}
			}
			int num4;
			if (_dotCount < _dots.Length)
			{
				num4 = _dotCount++;
			}
			else
			{
				num4 = _overwriteCursor++ % _dots.Length;
				if (_overwriteCursor >= _dots.Length)
				{
					_overwriteCursor = 0;
				}
				if (pulse.Automatic && num2 > now + 0.1f && _dots[num4].Birth <= now)
				{
					return;
				}
				RemoveCell(num4);
			}
			_dots[num4] = new Dot
			{
				Position = ((RaycastHit)(ref selected)).point + ((RaycastHit)(ref selected)).normal * 0.007f,
				Birth = num2,
				FadeInStart = (flag ? (num2 - 0.025f) : num2),
				Lifetime = num3,
				Strength = ReturnStrength(pulse, nearest),
				Color = (Color)(pulse.Clap ? new Color(0.65f, 0.98f, 1f, 1f) : ColorFor(pulse.Kind)),
				Indexed = pulse.Deduplicate,
				Cell = surfaceCell,
				Clap = pulse.Clap
			};
			if (pulse.Deduplicate)
			{
				_surfaceCells[surfaceCell] = num4;
			}
		}

		private static float ReturnStrength(Pulse pulse, float distance)
		{
			return pulse.Strength * Mathf.Lerp(1f, pulse.Clap ? 0.7f : 0.35f, distance / pulse.Range);
		}

		private ColliderFlags GetColliderFlags(Collider collider, Transform? rigRoot)
		{
			int instanceID = ((Object)collider).GetInstanceID();
			if (_colliderFlags.TryGetValue(instanceID, out var value) && (Object)(object)value.Collider == (Object)(object)collider)
			{
				return value;
			}
			Transform transform = ((Component)collider).transform;
			bool flag = (Object)(object)rigRoot != (Object)null && ((Object)(object)transform == (Object)(object)rigRoot || transform.IsChildOf(rigRoot));
			value = new ColliderFlags
			{
				Collider = collider,
				Local = flag,
				Player = (!flag && _players.IsPlayerTransform(transform))
			};
			if (_colliderFlags.Count < 512)
			{
				_colliderFlags[instanceID] = value;
			}
			return value;
		}

		private bool HasRecentNearbySound(Vector3 origin, float now, Collider? owner)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			RecentSound[] recentSounds = _recentSounds;
			for (int i = 0; i < recentSounds.Length; i++)
			{
				RecentSound recentSound = recentSounds[i];
				if (recentSound.Valid && (Object)(object)recentSound.Owner == (Object)(object)owner && now >= recentSound.Time && now - recentSound.Time < 0.18f)
				{
					Vector3 val = origin - recentSound.Origin;
					if (((Vector3)(ref val)).sqrMagnitude < 0.5625f)
					{
						return true;
					}
				}
			}
			return false;
		}

		private int NextPulseIndex(bool allowAutomatic)
		{
			int num = ClapPulseIndex();
			if (num >= 0)
			{
				return num;
			}
			bool flag = false;
			for (int i = 0; i < _pulseCount; i++)
			{
				if (_pulses[i].Kind == EchoKind.Manual && !_pulses[i].Sonar && !_pulses[i].Lidar)
				{
					flag = true;
				}
			}
			for (int j = 0; j < _pulseCount; j++)
			{
				int num2 = (_pulseCursor + j) % _pulseCount;
				if (!((_pulses[num2].Sonar || _pulses[num2].Lidar) && flag) && (allowAutomatic || !_pulses[num2].Automatic))
				{
					return num2;
				}
			}
			return -1;
		}

		private void Draw(float now, Transform head)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: 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_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: 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_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: 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_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: 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)
			//IL_027e: 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)
			int num = 0;
			float num2 = Mathf.Clamp(_settings.DotSize, 0.002f, 0.2f);
			float num3 = (float.IsFinite(_settings.DotBrightness) ? Mathf.Clamp(_settings.DotBrightness, 0.25f, 3f) : 1.8f);
			Vector3 val = head.right * num2;
			Vector3 val2 = head.up * num2;
			for (int i = 0; i < _dotCount; i++)
			{
				ref Dot reference = ref _dots[i];
				float num4 = now - reference.Birth;
				if (num4 < 0f)
				{
					continue;
				}
				float num5 = Mathf.Clamp01(1f - num4 / reference.Lifetime);
				float num6 = reference.Strength * num5 * num5 * Mathf.Clamp01((now - reference.FadeInStart) / 0.025f);
				if (!(num6 < 0.006f))
				{
					int num7 = num++ * 5;
					Color color = reference.Color;
					color.r *= num3;
					color.g *= num3;
					color.b *= num3;
					color.a = num6;
					((Il2CppArrayBase<Vector3>)(object)_vertices)[num7] = reference.Position;
					((Il2CppArrayBase<Color>)(object)_colors)[num7] = color;
					color.a = 0f;
					((Il2CppArrayBase<Vector3>)(object)_vertices)[num7 + 1] = reference.Position + val2;
					((Il2CppArrayBase<Vector3>)(object)_vertices)[num7 + 2] = reference.Position + val;
					((Il2CppArrayBase<Vector3>)(object)_vertices)[num7 + 3] = reference.Position - val2;
					((Il2CppArrayBase<Vector3>)(object)_vertices)[num7 + 4] = reference.Position - val;
					for (int j = 1; j <= 4; j++)
					{
						((Il2CppArrayBase<Color>)(object)_colors)[num7 + j] = color;
					}
				}
			}
			if (num != 0)
			{
				int num8 = num * 5;
				_mesh.Clear();
				_mesh.indexFormat = (IndexFormat)(num8 > 65535);
				_mesh.SetVertices(_vertices, 0, num8);
				_mesh.SetColors(_colors, 0, num8);
				_mesh.SetUVs(0, _uvs, 0, num8);
				_mesh.SetTriangles(_indices, 0, num * 12, 0, true, 0);
				Graphics.DrawMesh(_mesh, Matrix4x4.identity, _material, 0, (Camera)null, 0, (MaterialPropertyBlock)null, (ShadowCastingMode)0, false, (Transform)null, (LightProbeUsage)0, (LightProbeProxyVolume)null);
			}
		}

		private void EnsureCapacity(int capacity)
		{
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			if (_dots.Length != capacity)
			{
				for (int i = capacity; i < _dotCount; i++)
				{
					RemoveCell(i);
				}
				Array.Resize(ref _dots, capacity);
				_dotCount = Math.Min(_dotCount, capacity);
				_overwriteCursor = 0;
			}
			if (_uploadCapacity >= capacity)
			{
				return;
			}
			_uploadCapacity = capacity;
			_vertices = new Il2CppStructArray<Vector3>((long)(capacity * 5));
			_colors = new Il2CppStructArray<Color>((long)(capacity * 5));
			_uvs = new Il2CppStructArray<Vector2>((long)(capacity * 5));
			_indices = new Il2CppStructArray<int>((long)(capacity * 12));
			for (int j = 0; j < capacity; j++)
			{
				int num = j * 5;
				for (int k = 0; k < 5; k++)
				{
					((Il2CppArrayBase<Vector2>)(object)_uvs)[num + k] = new Vector2(0.5f, 0.5f);
				}
				for (int l = 0; l < 4; l++)
				{
					int num2 = j * 12 + l * 3;
					((Il2CppArrayBase<int>)(object)_indices)[num2] = num;
					((Il2CppArrayBase<int>)(object)_indices)[num2 + 1] = num + l + 1;
					((Il2CppArrayBase<int>)(object)_indices)[num2 + 2] = num + (l + 1) % 4 + 1;
				}
			}
		}

		private void ExpireDots(float now)
		{
			int num = 0;
			while (num < _dotCount)
			{
				if (now >= _dots[num].Birth + _dots[num].Lifetime)
				{
					RemoveCell(num);
					_dots[num] = _dots[--_dotCount];
					if (num < _dotCount && _dots[num].Indexed)
					{
						_surfaceCells[_dots[num].Cell] = num;
					}
				}
				else
				{
					num++;
				}
			}
		}

		private void RemoveCell(int slot)
		{
			if (_dots[slot].Indexed)
			{
				_surfaceCells.Remove(_dots[slot].Cell);
			}
		}

		private void PrunePulses(float now)
		{
			for (int num = _pulseCount - 1; num >= 0; num--)
			{
				if (((_pulses[num].Sonar || _pulses[num].Lidar) && now < _pulses[num].Time) || now - _pulses[num].Time > (_pulses[num].Clap ? 3f : (_pulses[num].Sonar ? 0.12f : (_pulses[num].Lidar ? 0.25f : 1.25f))))
				{
					RemovePulse(num);
				}
			}
		}

		private int ClapPulseIndex()
		{
			for (int i = 0; i < _pulseCount; i++)
			{
				if (_pulses[i].Clap)
				{
					return i;
				}
			}
			return -1;
		}

		private static int ReverseLowBits(int value, int bits)
		{
			int num = 0;
			for (int i = 0; i < bits; i++)
			{
				num = (num << 1) | (value & 1);
				value >>= 1;
			}
			return num;
		}

		private void RemovePulse(int index)
		{
			_pulses[index] = _pulses[--_pulseCount];
			if (_pulseCursor >= _pulseCount)
			{
				_pulseCursor = 0;
			}
		}

		private void EnsureAssets(float now)
		{
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Expected O, but got Unknown
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: 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_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Expected O, but got Unknown
			if (Ready || now < _nextShaderAttempt || _shaderAttempts >= 6)
			{
				return;
			}
			_shaderAttempts++;
			_nextShaderAttempt = now + 3f;
			DestroyAssets();
			try
			{
				Shader val = null;
				string[] shaderNames = ShaderNames;
				for (int i = 0; i < shaderNames.Length; i++)
				{
					Shader val2 = Shader.Find(shaderNames[i]);
					if ((Object)(object)val2 != (Object)null && val2.isSupported)
					{
						val = val2;
						break;
					}
				}
				if ((Object)(object)val == (Object)null)
				{
					if (_shaderAttempts == 1 || _shaderAttempts == 6)
					{
						_warning($"Echolocation: no supported depth-tested vertex-color shader (attempt {_shaderAttempts}/{6}).");
					}
					return;
				}
				_material = new Material(val)
				{
					hideFlags = (HideFlags)61,
					renderQueue = 3001
				};
				if (_material.HasProperty(