Decompiled source of Echolocation v1.7.5
Mods/Echolocation.dll
Decompiled 6 hours ago
The result has been truncated due to the large size, download it to view full contents!
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.Pool; using Il2CppSLZ.Marrow.PuppetMasta; 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.7.5", "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 int _clapPulseCount; 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.7.5 loaded. Closer walking/sound dots with 9cm merging and bounded automatic ray work. Gunshot echoes use the muzzle. No native audio patches. Controls in BoneMenu. F6 toggle; F5 pulse."); ((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_01be: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) if (_settings == null) { return; } _menu.EnsureBuilt(); ReadVisionGesture(); if (_settings.DesktopHotkeys) { if (Input.GetKeyDown((KeyCode)287)) { SetEnabled(!_settings.Enabled); } if (Input.GetKeyDown((KeyCode)286)) { ManualPulse(); } } Transform val = null; Transform val2 = null; try { val = Player.Head; if ((Object)(object)Player.RigManager != (Object)null) { val2 = ((Component)Player.RigManager).transform; } } catch (Exception) { } if (!_settings.Enabled || (Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { _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 { if (_settings.WorldSoundEnabled) { _worldMonitor.Tick(unscaledTime); } else { _worldMonitor.Reset(); } } catch (Exception ex4) { Warn("World playback monitoring: " + ex4.Message); } try { _world.Tick(unscaledTime, val.position, _emit, _observeSound); } catch (Exception ex5) { Warn("World sound input: " + ex5.Message); } FlushInput(unscaledTime); } public override void OnLateUpdate() { if (!_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 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() { 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); } } 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($"Vision: {_renderer.VisionStatus}; blackout setting={_settings.Blackout}"); ((MelonBase)this).LoggerInstance.Msg($"Players: {_renderer.PlayerStatus}; highlights={_settings.PlayerHighlights}"); ((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($"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) && !(source.spatialBlend < 0.5f) && (!source.loop || _settings.IncludeLoopingAudio) && !((Object)(object)_head == (Object)null)) { float unscaledTime = Time.unscaledTime; _world.RegisterPlayingSource(source, _objectSources.Capture(unscaledTime, source)); } } private void Emit(EchoEvent echo) { //IL_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 (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(); 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 sealed class EchoRenderer : IDisposable { private struct Pulse { internal Vector3 Origin; internal Quaternion Rotation; internal bool Clap; internal bool Automatic; internal bool Deduplicate; internal EchoKind Kind; internal SoundEmitterSurface? SurfaceEmission; internal Vector3 ListenerOrigin; internal int SurfaceRays; internal float Strength; internal float Time; internal float Range; internal float Phase; internal int Total; internal int Next; internal int ShuffleBits; internal int ShuffleCursor; } private struct Dot { internal Vector3 Position; internal 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 GoldenAngle = 2.3999631f; private const int ShaderAttempts = 6; private const int AutomaticRaysPerPulse = 512; private const int AutomaticRaysPerFrame = 256; private const int EmitterSurfaceRayLimit = 128; private const float AutomaticLifetime = 0.85f; private const float AutomaticDotSpacing = 0.09f; private const int ColliderCacheLimit = 512; private static readonly string[] ShaderNames = new string[3] { "Sprites/Default", "Legacy Shaders/Particles/Alpha Blended", "Hidden/Internal-Colored" }; private readonly Settings _settings; private readonly Action<string> _warning; private readonly BlackoutView _blackout; private readonly PlayerEchoes _players; private readonly 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; 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 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); } 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_0259: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_037b: Unknown result type (might be due to invalid IL or missing references) //IL_0380: 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) { bool flag2 = soundEmitterSurface != null && soundEmitterSurface.Count > 0; if (!clap && !flag2) { return false; } int num = -1; for (int i = 0; i < _pulseCount; i++) { if ((clap || (!_pulses[i].Clap && _pulses[i].Kind != EchoKind.Manual && _pulses[i].SurfaceEmission == null)) && (num < 0 || _pulses[i].Time < _pulses[num].Time)) { num = i; } } 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 j = 0; if (clap) { for (; 1 << j < num4; j++) { } } _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 = Mathf.Clamp(_settings.Range, 2f, 200f) * Mathf.Lerp(0.4f, 1f, num2), Total = num4, Phase = (float)(++_sequence % 65536) * 2.3999631f, Clap = clap, Automatic = flag, Deduplicate = _settings.OptimizeAutomaticEchoes, ShuffleBits = j }; 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_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) 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.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; _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_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_018f: 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_01dd: 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_01fc: 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.Clap) { int num4; do { num4 = ReverseLowBits(pulse.ShuffleCursor++, pulse.ShuffleBits); } while (num4 >= pulse.Total); float num5 = 1f - 2f * (((float)num4 + 0.5f) / (float)pulse.Total); float num6 = Mathf.Sqrt(Mathf.Max(0f, 1f - num5 * num5)); float num7 = (float)num4 * 2.3999631f + pulse.Phase; ((Vector3)(ref direction2))..ctor(num6 * Mathf.Cos(num7), num5, num6 * Mathf.Sin(num7)); } else if (num % 3 == 0) { float num8 = Mathf.Lerp(1f, 0.25f, num2); float num9 = Mathf.Sqrt(Mathf.Max(0f, 1f - num8 * num8)); direction2 = pulse.Rotation * new Vector3(num9 * Mathf.Cos(num3), num9 * Mathf.Sin(num3), num8); } else { float num10 = 1f - 2f * num2; float num11 = Mathf.Sqrt(Mathf.Max(0f, 1f - num10 * num10)); ((Vector3)(ref direction2))..ctor(num11 * Mathf.Cos(num3), num10, num11 * 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_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_0222: 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_022c: 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_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) float num = (pulse.Clap ? now : pulse.Time) + nearest / 45f; float num2 = Mathf.Clamp(_settings.DotLifetime, 0.15f, 8f); if (pulse.Clap) { num2 = Mathf.Max(2.5f, num2); } if (pulse.Automatic) { num2 = Math.Min(num2, 0.85f); } if (now >= num + num2) { 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(num, now) : Math.Min(reference.Birth, num)); reference.Lifetime = num2; 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 num3; if (_dotCount < _dots.Length) { num3 = _dotCount++; } else { num3 = _overwriteCursor++ % _dots.Length; if (_overwriteCursor >= _dots.Length) { _overwriteCursor = 0; } RemoveCell(num3); } _dots[num3] = new Dot { Position = ((RaycastHit)(ref selected)).point + ((RaycastHit)(ref selected)).normal * 0.007f, Birth = num, FadeInStart = num, Lifetime = num2, 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] = num3; } } 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; } for (int i = 0; i < _pulseCount; i++) { int num2 = (_pulseCursor + i) % _pulseCount; if (allowAutomatic || !_pulses[num2].Automatic) { return num2; } } return -1; } private void Draw(float now, Transform head) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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_0031: 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_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: 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_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0124: 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) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0156: 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_015c: 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_0176: 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); Vector3 val = head.right * num2; Vector3 val2 = head.up * num2; for (int i = 0; i < _dotCount; i++) { ref Dot reference = ref _dots[i]; float num3 = now - reference.Birth; if (num3 < 0f) { continue; } float num4 = Mathf.Clamp01(1f - num3 / reference.Lifetime); float num5 = reference.Strength * num4 * num4 * Mathf.Clamp01((now - reference.FadeInStart) / 0.025f); if (!(num5 < 0.006f)) { int num6 = num++ * 5; Color color = reference.Color; color.a = num5; ((Il2CppArrayBase<Vector3>)(object)_vertices)[num6] = reference.Position; ((Il2CppArrayBase<Color>)(object)_colors)[num6] = color; color.a = 0f; ((Il2CppArrayBase<Vector3>)(object)_vertices)[num6 + 1] = reference.Position + val2; ((Il2CppArrayBase<Vector3>)(object)_vertices)[num6 + 2] = reference.Position + val; ((Il2CppArrayBase<Vector3>)(object)_vertices)[num6 + 3] = reference.Position - val2; ((Il2CppArrayBase<Vector3>)(object)_vertices)[num6 + 4] = reference.Position - val; for (int j = 1; j <= 4; j++) { ((Il2CppArrayBase<Color>)(object)_colors)[num6 + j] = color; } } } if (num != 0) { int num7 = num * 5; _mesh.Clear(); _mesh.indexFormat = (IndexFormat)(num7 > 65535); _mesh.SetVertices(_vertices, 0, num7); _mesh.SetColors(_colors, 0, num7); _mesh.SetUVs(0, _uvs, 0, num7); _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 (now - _pulses[num].Time > (_pulses[num].Clap ? 3f : 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("_Color")) { _material.SetColor("_Color", Color.white); } if (_material.HasProperty("_MainTex")) { _material.SetTexture("_MainTex", (Texture)(object)Texture2D.whiteTexture); } SetIntIfPresent(_material, "_ZTest", 4); SetIntIfPresent(_material, "_ZWrite", 0); SetIntIfPresent(_material, "_Cull", 0); SetIntIfPresent(_material, "_SrcBlend", 5); SetIntIfPresent(_material, "_DstBlend", 10); _mesh = new Mesh { name = "Echolocation.SurfaceReturns", hideFlags = (HideFlags)61 }; _mesh.MarkDynamic(); } catch (Exception ex) { DestroyAssets(); if (_shaderAttempts == 1 || _shaderAttempts == 6) { _warning($"Echolocation render initialization failed ({_shaderAttempts}/{6}): {ex.Message}"); } } } 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; } private static void SetIntIfPresent(Material material, string property, int value) { if (material.HasProperty(property)) { material.SetInt(property, value); } } 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; } private static Color ColorFor(EchoKind kind) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: 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_007e: 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) return (Color)(kind switch { EchoKind.Footstep => new Color(0.25f, 1f, 0.42f, 1f), EchoKind.World => new Color(1f, 0.55f, 0.16f, 1f), EchoKind.Voice => new Color(0.78f, 0.42f, 1f, 1f), _ => new Color(0.16f, 0.88f, 1f, 1f), }); } } internal sealed class EchoReveal { private struct Window { internal float Start; internal float Duration; internal float Strength; } private readonly Window[] _windows = new Window[4]; private int _next; internal void Schedule(float arrival, float lifetime, float strength) { if (float.IsFinite(arrival) && float.IsFinite(lifetime) && !(lifetime <= 0f) && float.IsFinite(strength)) { _windows[_next] = new Window { Start = arrival, Duration = Math.Clamp(lifetime, 0.1f, 5f), Strength = Math.Clamp(strength, 0f, 1f) }; _next = (_next + 1) % _windows.Length; } } internal float Opacity(float now) { if (!float.IsFinite(now)) { return 0f; } float num = 0f; Window[] windows = _windows; for (int i = 0; i < windows.Length; i++) { Window window = windows[i]; float num2 = now - window.Start; if (!(window.Duration <= 0f) && !(num2 < 0f) && !(num2 >= window.Duration)) { float num3 = 1f - num2 / window.Duration; num = Math.Max(num, window.Strength * num3 * num3); } } return num; } internal void Clear() { Array.Clear(_windows, 0, _windows.Length); _next = 0; } } internal sealed class FusionBridge { private readonly Settings _settings; private readonly Action<string> _warning; private readonly Dictionary<int, PulseGate> _voiceGates = new Dictionary<int, PulseGate>(); private readonly HashSet<int> _seenSources = new HashSet<int>(); private readonly List<int> _expiredSources = new List<int>(); private readonly Il2CppStructArray<float> _outputSamples = new Il2CppStructArray<float>(128L); private Func<float>? _localAmplitude; private Func<bool>? _hasServer; private Func<bool>? _isMuted; private Func<bool>? _isDeafened; private Func<bool>? _canTalk; private Func<bool>? _hasVoiceActivity; private Func<byte>? _localID; private PropertyInfo? _manager; private PropertyInfo? _voices; private PropertyInfo? _sourceAmplitude; private PropertyInfo? _sourcePlaying; private PropertyInfo? _sourceID; private PropertyInfo? _sourceAudio; private float _nextDiscovery; private bool _failed; internal bool Present { get; private set; } internal string Status { get; private set; } = "Standalone microphone"; internal FusionBridge(Settings settings, Action<string> warning) { _settings = settings; _warning = warning; } internal void Discover(float now) { if (Present || now < _nextDiscovery) { return; } _nextDiscovery = now + 1f; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (string.Equals(assembly.GetName().Name, "LabFusion", StringComparison.Ordinal)) { Present = true; try { Type type = RequiredType(assembly, "LabFusion.Voice.VoiceInfo"); Type type2 = RequiredType(assembly, "LabFusion.Voice.VoiceSourceManager"); Type type3 = RequiredType(assembly, "LabFusion.Voice.VoiceSource"); _localAmplitude = StaticGetter<float>(type, "VoiceAmplitude"); _isMuted = StaticGetter<bool>(type, "IsMuted"); _isDeafened = StaticGetter<bool>(type, "IsDeafened"); _canTalk = StaticGetter<bool>(type, "CanTalk"); _hasVoiceActivity = StaticGetter<bool>(type, "HasVoiceActivity"); _hasServer = StaticGetter<bool>(RequiredType(assembly, "LabFusion.Network.NetworkInfo"), "HasServer"); _localID = StaticGetter<byte>(RequiredType(assembly, "LabFusion.Player.PlayerIDManager"), "LocalSmallID"); _manager = RequiredProperty(type, "VoiceManager"); _voices = RequiredProperty(type2, "ActiveVoices"); _sourceAmplitude = RequiredProperty(type3, "Amplitude"); _sourcePlaying = RequiredProperty(type3, "Playing"); _sourceID = RequiredProperty(type3, "ID"); _sourceAudio = RequiredProperty(type3, "AudioSource"); Status = "Fusion detected; join a session and enable voice chat for mic echoes"; break; } catch (Exception error) { Fail(error); break; } } } } internal float ReadLocalLevel() { if (!Present || _failed) { return 0f; } try { Func<bool>? hasServer = _hasServer; if (hasServer == null || !hasServer() || _manager?.GetValue(null) == null) { Status = "Fusion: join a session and enable voice chat for mic echoes"; return 0f; } Func<bool>? isMuted = _isMuted; if (isMuted == null || isMuted()) { Status = "Fusion: microphone echoes follow voice mute/deafen settings"; return 0f; } Status = "Fusion microphone meter (voice chat)"; Func<bool>? canTalk = _canTalk; if (canTalk != null && canTalk()) { Func<bool>? hasVoiceActivity = _hasVoiceActivity; if (hasVoiceActivity != null && hasVoiceActivity()) { return Sanitize((_localAmplitude?.Invoke() ?? 0f) * 0.1f); } } return 0f; } catch (Exception error) { Fail(error); return 0f; } } internal void TickRemote(float now, Vector3 head, Action<EchoEvent> emit, Action<EchoEvent>? observeSound = null) { //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: 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_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Unknown result type (might be due to invalid IL or missing references) if (!Present || _failed || !_settings.FusionVoiceEnabled) { _voiceGates.Clear(); return; } try { Func<bool>? hasServer = _hasServer; if (hasServer != null && hasServer()) { Func<bool>? isDeafened = _isDeafened; if (isDeafened != null && !isDeafened() && _voices?.GetValue(null) is IList list) { _seenSources.Clear(); int num = _localID?.Invoke() ?? 0; float num2 = Mathf.Clamp(_settings.WorldRange, 1f, 200f); for (int i = 0; i < Math.Min(list.Count, 128); i++) { object obj = list[i]; Component val = (Component)((obj is Component) ? obj : null); if (val == null || !Object.op_Implicit((Object)(object)val)) { continue; } int instanceID = ((Object)val).GetInstanceID(); _seenSources.Add(instanceID); int num3 = Convert.ToInt32(_sourceID.GetValue(obj)); if (num3 < 0 || num3 > 255 || num3 == num) { continue; } object value = _sourcePlaying.GetValue(obj); if (!(value is bool) || !(bool)value) { continue; } object? value2 = _sourceAudio.GetValue(obj); AudioSource val2 = (AudioSource)((value2 is AudioSource) ? value2 : null); if (val2 == null || !Object.op_Implicit((Object)(object)val2) || val2.mute || val2.volume <= 0f || !val2.isPlaying || val2.isVirtual || (AudioListener.pause && !val2.ignoreListenerPause)) { continue; } Vector3 position = val.transform.position; if (!(Vector3.Distance(head, position) > num2)) { float num4 = Sanitize(Convert.ToSingle(_sourceAmplitude.GetValue(obj)) * 0.1f * Mathf.Clamp01(val2.volume)); val2.GetOutputData(_outputSamples, 0); double num5 = 0.0; for (int j = 0; j < ((Il2CppArrayBase<float>)(object)_outputSamples).Length; j++) { num5 += (double)(((Il2CppArrayBase<float>)(object)_outputSamples)[j] * ((Il2CppArrayBase<float>)(object)_outputSamples)[j]); } float num6 = (val2.ignoreListenerVolume ? 1f : Mathf.Clamp01(AudioListener.volume)); float num7 = Sanitize((float)Math.Sqrt(num5 / (double)((Il2CppArrayBase<float>)(object)_outputSamples).Length) * val2.volume * num6); num4 = Mathf.Min(num4, num7); float strength = Mathf.Clamp01(num4 / Mathf.Max(0.01f, _settings.MicThreshold * 4f)); EchoEvent obj2 = new EchoEvent(position, strength, EchoKind.Voice, now, num3, val2); if (num4 >= Mathf.Clamp(_settings.MicThreshold, 0.0001f, 1f)) { observeSound?.Invoke(obj2); } if (!_voiceGates.TryGetValue(instanceID, out PulseGate value3)) { value3 = new PulseGate(); _voiceGates.Add(instanceID, value3); } if (value3.TryFire(now, num4, _settings.MicThreshold, _settings.MicCooldown)) { emit(obj2); } } } _expiredSources.Clear(); foreach (int key in _voiceGates.Keys) { if (!_seenSources.Contains(key)) { _expiredSources.Add(key); } } { foreach (int expiredSource in _expiredSources) { _voiceGates.Remove(expiredSource); } return; } } } _voiceGates.Clear(); } catch (Exception error) { Fail(error); } } internal void Reset() { _voiceGates.Clear(); _seenSources.Clear(); _expiredSources.Clear(); if (_failed) { Present = false; _failed = false; _nextDiscovery = 0f; } } private void Fail(Exception error) { _failed = true; Status = "Fusion voice API unavailable; microphone left to Fusion"; _warning("Fusion voice integration disabled: " + error.GetBaseException().Message); } private static Type RequiredType(Assembly assembly, string name) { return assembly.GetType(name, throwOnError: true); } private static PropertyInfo RequiredProperty(Type type, string name) { return type.GetProperty(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public) ?? throw new MissingMemberException(type.FullName, name); } private static Func<T> StaticGetter<T>(Type type, string name) { return RequiredProperty(type, name).GetMethod.CreateDelegate<Func<T>>(); } private static float Sanitize(float level) { if (!float.IsFinite(level)) { return 0f; } return Mathf.Clamp01(level); } } internal sealed class LocomotionInput { private readonly Settings _settings; private readonly Il2CppStructArray<RaycastHit> _groundHits = new Il2CppStructArray<RaycastHit>(16L); private bool _initialized; private bool _wasGrounded; private Vector3 _lastPosition; private float _lastTime; private float _nextSample; private float _distance; private float _lastStep = float.NegativeInfinity; private float _airborneSince; private float _fallSpeed; private Transform? _lastSurface; private Vector3 _lastLocalPosition; private int _lastTracker; public string Status { get; private set; } = "Waiting for player"; public LocomotionInput(Settings settings) { _settings = settings; } public void Tick(float now, Transform head, Transform? rigRoot, Action<EchoEvent> emit) { //IL_00ab: 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_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_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_0158: 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_0165: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: 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_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_0217: 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_0204: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_0439: Unknown result type (might be due to invalid IL or missing references) //IL_043b: Unknown result type (might be due to invalid IL or missing references) //IL_044b: 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_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_03df: Unknown result type (might be due to invalid IL or missing references) //IL_03e1: Unknown result type (might be due to invalid IL or missing references) //IL_03eb: Unknown result type (might be due to invalid IL or missing references) //IL_03f0: Unknown result type (might be due to invalid IL or missing references) if (!_settings.FootstepsEnabled || (Object)(object)head == (Object)null) { Reset(); Status = (_settings.FootstepsEnabled ? "Waiting for player" : "Footsteps disabled"); } else { if (now < _nextSample) { return; } _nextSample = now + 0.05f; try { PhysicsRig physicsRig = Player.PhysicsRig; Transform val = (Transform)(((Object)(object)rigRoot != (Object)null) ? ((object)rigRoot) : ((object)head)); float num = 0.2f; GameObject val2 = (((Object)(object)physicsRig != (Object)null) ? physicsRig.feet : null); bool flag = (Object)(object)val2 != (Object)null; if (flag) { val = val2.transform; num = Mathf.Clamp(physicsRig.footballRadius, 0.05f, 1.5f); } Vector3 position = val.position; Vector3 origin = position + Vector3.up * 0.15f; float length = num + 0.4f; if (!flag && (Object)(object)rigRoot == (Object)null) { origin = head.position; length = 1.9f; } Vector3 contact; Transform surface; bool flag2 = TryGround(origin, length, rigRoot, out contact, out surface); bool flag3 = ((!flag) ? flag2 : (physicsRig.footSupported > 0.05f && !physicsRig.ungroundedThisFrame && physicsRig.onLadder == 0)); if (!flag2) { contact = position - Vector3.up * num; surface = null; } int instanceID = ((Object)val).GetInstanceID(); float num2 = now - _lastTime; Vector3 val3 = position - _lastPosition; if (!_initialized || instanceID != _lastTracker || num2 <= 0f || num2 > 0.5f || ((Vector3)(ref val3)).magnitude > Mathf.Max(1.5f, num2 * 14f)) { BeginSample(now, position, instanceID, flag3, surface); return; } Vector3 val4 = val3; if ((Object)(object)surface != (Object)null && (Object)(object)_lastSurface != (Object)null && (Object)(object)surface == (Object)(object)_lastSurface) { val4 = position - surface.TransformPoint(_lastLocalPosition); } else if (flag) { val4 -= physicsRig.groundVelocity * num2; } float num3 = val3.y / num2; if (!flag3) { if (_wasGrounded) { _airborneSince = now; _fallSpeed = 0f; } _fallSpeed = Mathf.Max(_fallSpeed, 0f - num3); _distance = 0f; Status = "Airborne or climbing"; } else { if (!_wasGrounded) { if (now - _airborneSince > 0.15f && _fallSpeed > 0.8f && now - _lastStep > 0.2f) { float strength = Mathf.Lerp(0.4f, 1f, Mathf.Clamp01((_fallSpeed - 0.8f) / 6f)); emit(new EchoEvent(contact + Vector3.up * 0.05f, strength, EchoKind.Footstep, now)); _lastStep = now; } _fallSpeed = 0f; _distance = 0f; } val4.y = 0f; float magnitude = ((Vector3)(ref val4)).magnitude; float num4 = magnitude / num2; Status = "Tracking grounded footsteps"; if (_wasGrounded && num4 >= 0.18f && num4 < 12f) { _distance += magnitude; float num5 = Mathf.Clamp(_settings.StepDistance, 0.25f, 2f); if (_distance >= num5 && now - _lastStep >= 0.18f) { _distance %= num5; _lastStep = now; float strength2 = Mathf.Lerp(0.3f, 0.85f, Mathf.Clamp01(num4 / 6f)); emit(new EchoEvent(contact + Vector3.up * 0.05f, strength2, EchoKind.Footstep, now)); } } else if (num4 < 0.18f) { _distance = Mathf.Max(0f, _distance - num2 * 0.6f); } } _lastTime = now; _lastPosition = position; _wasGrounded = flag3; RememberSurface(surface, position); } catch (Exception ex) { Reset(); _nextSample = now + 0.5f; Status = "Player physics unavailable: " + ex.GetType().Name; } } } private bool TryGround(Vector3 origin, float length, Transform? rigRoot, out Vector3 contact, out Transform? surface) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) contact = origin; surface = null; int num = Physics.RaycastNonAlloc(origin, Vector3.down, _groundHits, length, -5, (QueryTriggerInteraction)1); float num2 = float.PositiveInfinity; for (int i = 0; i < num; i++) { RaycastHit val = ((Il2CppArrayBase<RaycastHit>)(object)_groundHits)[i]; if (!((Object)(object)((RaycastHit)(ref val)).collider == (Object)null) && !(((RaycastHit)(ref val)).distance >= num2) && !(((RaycastHit)(ref val)).normal.y < 0.5f)) { Transform transform = ((Component)((RaycastHit)(ref val)).collider).transform; if (!((Object)(object)rigRoot != (Object)null) || (!((Object)(object)transform == (Object)(object)rigRoot) && !transform.IsChildOf(rigRoot))) { contact = ((RaycastHit)(ref val)).point; surface = transform; num2 = ((RaycastHit)(ref val)).distance; } } } return (Object)(object)surface != (Object)null; } private void BeginSample(float now, Vector3 position, int trackerId, bool grounded, Transform? surface) { //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_0044: Unknown result type (might be due to invalid IL or missing references) _initialized = true; _lastPosition = position; _lastTracker = trackerId; _lastTime = now; _wasGrounded = grounded; _distance = 0f; _fallSpeed = 0f; _airborneSince = now; RememberSurface(surface, position); } private void RememberSurface(Transform? surface, Vector3 position) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) _lastSurface = surface; if ((Object)(object)surface != (Object)null) { _lastLocalPosition = surface.InverseTransformPoint(position); } } public void Reset() { _initialized = false; _wasGrounded = false; _lastSurface = null; _distance = 0f; _fallSpeed = 0f; _lastStep = float.NegativeInfinity; _nextSample = 0f; Status = "Waiting for player"; } } internal sealed class MenuPage { private readonly Settings _settings; private readonly EcholocationMod _mod; private readonly Action<string> _warning; private Page? _page; private int _section; private float _nextTry; private static readonly Color Accent = new Color(0.2f, 0.95f, 1f); public MenuPage(Settings settings, EcholocationMod mod, Action<string> warning) { _settings = settings; _mod = mod; _warning = warning; } public void EnsureBuilt() { //IL_0047: Unknown result type (might be due to invalid IL or missing references) if (_section >= 4 || Time.unscaledTime < _nextTry) { return; } _nextTry = Time.unscaledTime + 2f; try { if (Page.Root == null) { return; } if (_page == null) { _page = Page.Root.CreatePage("Echolocation", Accent, 0, true); } while (_section < 4) { switch (_section++) { case 0: Main(_page); break; case 1: Input(_page); break; case 2: Visuals(_page); break; case 3: Advanced(_page); break; } } } catch (Exception ex) { _warning("BoneMenu: " + ex.Message); } } private void Main(Page page) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: 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_012d: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) page.CreateBool("Enabled", Accent, _settings.Enabled, (Action<bool>)_mod.SetEnabled); page.CreateBool("Blackout (Echolocation Only)", Accent, _settings.Blackout, (Action<bool>)_mod.SetBlackout); page.CreateBool("Double Clap: 360 Pulse", Accent, _settings.DoubleClapEnabled, (Action<bool>)_mod.SetDoubleClap); page.CreateBool("Clap and Pulse Sounds", Accent, _settings.PulseSoundEnabled, (Action<bool>)_mod.SetPulseSound); page.CreateFloat("Pulse Sound Volume", Accent, _settings.PulseSoundVolume, 0.05f, 0f, 1f, (Action<float>)delegate(float value) { _settings.PulseSoundVolume = value; _mod.Save(); }); page.CreateFloat("Clap Distance (Larger = Easier)", Accent, _settings.ClapContactDistance, 0.025f, 0.15f, 0.45f, (Action<float>)_mod.SetClapDistance); page.CreateFunction("Test Pulse Sound", Accent, (Action)_mod.TestPulseSound); page.CreateFunction("Send Pulse", Color.green, (Action)_mod.ManualPulse); page.CreateFunction("Print Input Levels to Console", Accent, (Action)_mod.Diagnostics); } private void Input(Page root) { //IL_0006: 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_0040: 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_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown r