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 _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? _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 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 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)(object)val).Length) { Camera val2 = ((Il2CppArrayBase)(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)(object)val).Length) { if ((Object)(object)((Il2CppArrayBase)(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 val = Object.FindObjectsOfType(); 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() : 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)(object)_cameraBuffer).Length < allCamerasCount) { _cameraBuffer = new Il2CppReferenceArray((long)Math.Max(32, allCamerasCount)); } allCamerasCount = Camera.GetAllCameras(_cameraBuffer); for (int j = 0; j < allCamerasCount; j++) { Camera val4 = ((Il2CppArrayBase)(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 val = new Il2CppStructArray((long)array.Length); Il2CppStructArray val2 = new Il2CppStructArray((long)array.Length); Il2CppStructArray val3 = new Il2CppStructArray((long)array.Length); Il2CppStructArray val4 = new Il2CppStructArray((long)(array2.Length * 2)); for (int i = 0; i < array.Length; i++) { ((Il2CppArrayBase)(object)val)[i] = array[i]; ((Il2CppArrayBase)(object)val2)[i] = Color.black; ((Il2CppArrayBase)(object)val3)[i] = new Vector2(0.5f, 0.5f); } for (int j = 0; j < array2.Length; j += 3) { ((Il2CppArrayBase)(object)val4)[j] = array2[j]; ((Il2CppArrayBase)(object)val4)[j + 1] = array2[j + 1]; ((Il2CppArrayBase)(object)val4)[j + 2] = array2[j + 2]; ((Il2CppArrayBase)(object)val4)[array2.Length + j] = array2[j]; ((Il2CppArrayBase)(object)val4)[array2.Length + j + 1] = array2[j + 2]; ((Il2CppArrayBase)(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)(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 _emit; private Action _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)(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 { 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 _warning; private readonly BlackoutView _blackout; private readonly PlayerEchoes _players; private readonly Pulse[] _pulses = new Pulse[4]; private readonly Il2CppStructArray _hits = new Il2CppStructArray(32L); private readonly Dictionary _surfaceCells = new Dictionary(); private readonly Dictionary _colliderFlags = new Dictionary(512); private readonly RecentSound[] _recentSounds = new RecentSound[8]; private int _recentSoundCursor; private Dot[] _dots = Array.Empty(); private int _dotCount; private int _pulseCount; private int _pulseCursor; private int _overwriteCursor; private uint _sequence; private Mesh? _mesh; private Material? _material; private Il2CppStructArray? _vertices; private Il2CppStructArray? _colors; private Il2CppStructArray? _uvs; private Il2CppStructArray? _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 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(); _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)(object)_hits).Length) { return false; } float num2 = float.PositiveInfinity; bool flag = false; for (int i = 0; i < num; i++) { RaycastHit val = ((Il2CppArrayBase)(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)(object)_vertices)[num6] = reference.Position; ((Il2CppArrayBase)(object)_colors)[num6] = color; color.a = 0f; ((Il2CppArrayBase)(object)_vertices)[num6 + 1] = reference.Position + val2; ((Il2CppArrayBase)(object)_vertices)[num6 + 2] = reference.Position + val; ((Il2CppArrayBase)(object)_vertices)[num6 + 3] = reference.Position - val2; ((Il2CppArrayBase)(object)_vertices)[num6 + 4] = reference.Position - val; for (int j = 1; j <= 4; j++) { ((Il2CppArrayBase)(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((long)(capacity * 5)); _colors = new Il2CppStructArray((long)(capacity * 5)); _uvs = new Il2CppStructArray((long)(capacity * 5)); _indices = new Il2CppStructArray((long)(capacity * 12)); for (int j = 0; j < capacity; j++) { int num = j * 5; for (int k = 0; k < 5; k++) { ((Il2CppArrayBase)(object)_uvs)[num + k] = new Vector2(0.5f, 0.5f); } for (int l = 0; l < 4; l++) { int num2 = j * 12 + l * 3; ((Il2CppArrayBase)(object)_indices)[num2] = num; ((Il2CppArrayBase)(object)_indices)[num2 + 1] = num + l + 1; ((Il2CppArrayBase)(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 _warning; private readonly Dictionary _voiceGates = new Dictionary(); private readonly HashSet _seenSources = new HashSet(); private readonly List _expiredSources = new List(); private readonly Il2CppStructArray _outputSamples = new Il2CppStructArray(128L); private Func? _localAmplitude; private Func? _hasServer; private Func? _isMuted; private Func? _isDeafened; private Func? _canTalk; private Func? _hasVoiceActivity; private Func? _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 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(type, "VoiceAmplitude"); _isMuted = StaticGetter(type, "IsMuted"); _isDeafened = StaticGetter(type, "IsDeafened"); _canTalk = StaticGetter(type, "CanTalk"); _hasVoiceActivity = StaticGetter(type, "HasVoiceActivity"); _hasServer = StaticGetter(RequiredType(assembly, "LabFusion.Network.NetworkInfo"), "HasServer"); _localID = StaticGetter(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? 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? isMuted = _isMuted; if (isMuted == null || isMuted()) { Status = "Fusion: microphone echoes follow voice mute/deafen settings"; return 0f; } Status = "Fusion microphone meter (voice chat)"; Func? canTalk = _canTalk; if (canTalk != null && canTalk()) { Func? 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 emit, Action? 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? hasServer = _hasServer; if (hasServer != null && hasServer()) { Func? 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)(object)_outputSamples).Length; j++) { num5 += (double)(((Il2CppArrayBase)(object)_outputSamples)[j] * ((Il2CppArrayBase)(object)_outputSamples)[j]); } float num6 = (val2.ignoreListenerVolume ? 1f : Mathf.Clamp01(AudioListener.volume)); float num7 = Sanitize((float)Math.Sqrt(num5 / (double)((Il2CppArrayBase)(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 StaticGetter(Type type, string name) { return RequiredProperty(type, name).GetMethod.CreateDelegate>(); } 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 _groundHits = new Il2CppStructArray(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 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)(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 _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 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)_mod.SetEnabled); page.CreateBool("Blackout (Echolocation Only)", Accent, _settings.Blackout, (Action)_mod.SetBlackout); page.CreateBool("Double Clap: 360 Pulse", Accent, _settings.DoubleClapEnabled, (Action)_mod.SetDoubleClap); page.CreateBool("Clap and Pulse Sounds", Accent, _settings.PulseSoundEnabled, (Action)_mod.SetPulseSound); page.CreateFloat("Pulse Sound Volume", Accent, _settings.PulseSoundVolume, 0.05f, 0f, 1f, (Action)delegate(float value) { _settings.PulseSoundVolume = value; _mod.Save(); }); page.CreateFloat("Clap Distance (Larger = Easier)", Accent, _settings.ClapContactDistance, 0.025f, 0.15f, 0.45f, (Action)_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 result type (might be due to invalid IL or missing references) //IL_0126: 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) Page obj = root.CreatePage("Sound Inputs", Accent, 0, true); obj.CreateBool("Microphone", Accent, _settings.MicrophoneEnabled, (Action)delegate(bool value) { _settings.MicrophoneEnabled = value; _mod.RestartMicrophone(); _mod.Save(); }); obj.CreateBool("Walking and Landing", Accent, _settings.FootstepsEnabled, (Action)delegate(bool value) { _settings.FootstepsEnabled = value; _mod.Save(); }); obj.CreateBool("Nearby Game Sounds", Accent, _settings.WorldSoundEnabled, (Action)delegate(bool value) { _settings.WorldSoundEnabled = value; _mod.Save(); }); obj.CreateBool("Fusion Player Voices", Accent, _settings.FusionVoiceEnabled, (Action)delegate(bool value) { _settings.FusionVoiceEnabled = value; _mod.Save(); }); obj.CreateFloat("Mic Threshold (Lower = More Sensitive)", Accent, _settings.MicThreshold, 0.005f, 0.001f, 0.3f, (Action)delegate(float value) { _settings.MicThreshold = value; _mod.Save(); }); obj.CreateFloat("Game Sound Threshold", Accent, _settings.SoundThreshold, 0.005f, 0.001f, 0.3f, (Action)delegate(float value) { _settings.SoundThreshold = value; _mod.Save(); }); obj.CreateFloat("Hearing Range (m)", Accent, _settings.WorldRange, 5f, 5f, 200f, (Action)delegate(float value) { _settings.WorldRange = value; _mod.Save(); }); obj.CreateBool("Include Looping 3D Sounds", Accent, _settings.IncludeLoopingAudio, (Action)delegate(bool value) { _settings.IncludeLoopingAudio = value; _mod.Save(); }); } private void Visuals(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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) Page obj = root.CreatePage("Sonar Visuals", Accent, 0, true); obj.CreateBool("Optimize Walking and Sound Echoes", Accent, _settings.OptimizeAutomaticEchoes, (Action)delegate(bool value) { _settings.OptimizeAutomaticEchoes = value; _mod.Save(); }); obj.CreateBool("Players: Green Visible / Red Blocked", Accent, _settings.PlayerHighlights, (Action)delegate(bool value) { _settings.PlayerHighlights = value; _mod.Save(); }); obj.CreateFloat("Reveal Range (m)", Accent, _settings.Range, 4f, 4f, 200f, (Action)delegate(float value) { _settings.Range = value; _mod.Save(); }); obj.CreateFloat("Dot Lifetime (seconds)", Accent, _settings.DotLifetime, 0.2f, 0.4f, 5f, (Action)delegate(float value) { _settings.DotLifetime = value; _mod.Save(); }); obj.CreateFloat("Dot Size (m)", Accent, _settings.DotSize, 0.001f, 0.002f, 0.2f, (Action)delegate(float value) { _settings.DotSize = value; _mod.Save(); }); obj.CreateInt("Rays Per Pulse", Accent, _settings.RayCount, 128, 128, 16384, (Action)delegate(int value) { _settings.RayCount = value; _mod.Save(); }); obj.CreateInt("Ray Budget Per Frame", Accent, _settings.RaysPerFrame, 32, 32, 4096, (Action)delegate(int value) { _settings.RaysPerFrame = value; _mod.Save(); }); obj.CreateInt("Maximum Surface Dots", Accent, _settings.MaxDots, 512, 512, 65536, (Action)delegate(int value) { _settings.MaxDots = value; _mod.Save(); }); } private void Advanced(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_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) Page obj = root.CreatePage("Advanced", Accent, 0, true); obj.CreateInt("Solo Mic Device (-1 = Default)", Accent, _settings.MicrophoneDeviceIndex, 1, -1, 16, (Action)delegate(int value) { _settings.MicrophoneDeviceIndex = value; _mod.RestartMicrophone(); _mod.Save(); }); obj.CreateFunction("Restart Mic / Refresh Fusion", Accent, (Action)_mod.RestartMicrophone); obj.CreateFloat("Mic Pulse Interval (seconds)", Accent, _settings.MicCooldown, 0.05f, 0.15f, 2f, (Action)delegate(float value) { _settings.MicCooldown = value; _mod.Save(); }); obj.CreateFloat("Step Distance (m)", Accent, _settings.StepDistance, 0.1f, 0.3f, 2f, (Action)delegate(float value) { _settings.StepDistance = value; _mod.Save(); }); obj.CreateBool("Desktop F5/F6 Hotkeys", Accent, _settings.DesktopHotkeys, (Action)delegate(bool value) { _settings.DesktopHotkeys = value; _mod.Save(); }); } } internal sealed class MicrophoneInput : IDisposable { private const float PollInterval = 0.05f; private const int BufferSamples = 512; private readonly Settings _settings; private readonly Action _warning; private readonly FusionBridge _fusion; private readonly PulseGate _gate = new PulseGate(); private Il2CppStructArray? _samples; private AudioClip? _clip; private string? _device; private bool _ownsRecording; private bool _disposed; private int _selectedIndex = int.MinValue; private int _lastPosition = -1; private int _capturedFrames; private float _nextPoll; private float _nextAttempt; private string? _lastWarning; internal string Status { get; private set; } = "Starting microphone input"; internal float Level { get; private set; } internal MicrophoneInput(Settings settings, Action warning) { _settings = settings; _warning = warning; _fusion = new FusionBridge(settings, warning); } internal void Tick(float now, Vector3 head, Action emit, Action? observeSound = null) { //IL_0032: 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) if (_disposed || now < _nextPoll) { return; } _nextPoll = now + 0.05f; _fusion.Discover(now); _fusion.TickRemote(now, head, emit, observeSound); if (!_settings.MicrophoneEnabled) { ReleaseMicrophone(); Level = 0f; _gate.Reset(); Status = "Microphone echoes disabled"; return; } if (_fusion.Present) { ReleaseMicrophone(); Level = _fusion.ReadLocalLevel(); Status = _fusion.Status; } else { if (_selectedIndex != _settings.MicrophoneDeviceIndex) { Restart(); } _selectedIndex = _settings.MicrophoneDeviceIndex; Level = ReadStandalone(now); } if (_gate.TryFire(now, Level, _settings.MicThreshold, _settings.MicCooldown)) { float strength = Mathf.Clamp01(Level / Mathf.Max(0.01f, _settings.MicThreshold * 4f)); emit(new EchoEvent(head, strength, EchoKind.Microphone, now)); } } internal void Restart() { ReleaseMicrophone(); _gate.Reset(); _fusion.Reset(); _nextAttempt = 0f; _nextPoll = 0f; _lastWarning = null; Level = 0f; } private float ReadStandalone(float now) { try { if (!_ownsRecording) { if (now < _nextAttempt) { return 0f; } _nextAttempt = now + 5f; Il2CppStringArray devices = Microphone.devices; if (devices == null || ((Il2CppArrayBase)(object)devices).Length == 0) { Status = "No microphone found"; return 0f; } int microphoneDeviceIndex = _settings.MicrophoneDeviceIndex; if (microphoneDeviceIndex >= ((Il2CppArrayBase)(object)devices).Length || microphoneDeviceIndex < -1) { Status = "Microphone device index is out of range"; WarnOnce(Status); return 0f; } _device = ((microphoneDeviceIndex < 0) ? null : ((Il2CppArrayBase)(object)devices)[microphoneDeviceIndex]); if (Microphone.IsRecording(_device)) { Status = "Microphone is already owned by another recorder"; return 0f; } int num = default(int); int num2 = default(int); Microphone.GetDeviceCaps(_device, ref num, ref num2); int num3 = 48000; if (num > 0) { num3 = Math.Max(num3, num); } if (num2 > 0) { num3 = Math.Min(num3, num2); } _clip = Microphone.Start(_device, true, 1, num3); if (!Object.op_Implicit((Object)(object)_clip)) { Status = "Microphone could not start; check input permissions"; WarnOnce(Status); return 0f; } _ownsRecording = true; if (_samples == null) { _samples = new Il2CppStructArray(512L); } _lastPosition = 0; _capturedFrames = 0; Status = "Listening: " + ((microphoneDeviceIndex < 0) ? "default microphone" : ((Il2CppArrayBase)(object)devices)[microphoneDeviceIndex]); return 0f; } if ((Object)(object)_clip == (Object)null || !Object.op_Implicit((Object)(object)_clip) || !Microphone.IsRecording(_device)) { _ownsRecording = false; ReleaseMicrophone(); Status = "Microphone stopped; retrying"; _nextAttempt = now + 2f; return 0f; } int position = Microphone.GetPosition(_device); if (position < 0 || position == _lastPosition) { return 0f; } int samples = _clip.samples; int num4 = Math.Max(1, _clip.channels); int num5 = 512 / num4; if (samples <= num5 || num5 <= 0) { return 0f; } int num6 = position - _lastPosition; if (num6 < 0) { num6 += samples; } _capturedFrames = Math.Min(samples, _capturedFrames + num6); _lastPosition = position; if (_capturedFrames < num5) { return 0f; } int num7 = (position - num5 + samples) % samples; if (!_clip.GetData(_samples, num7)) { return 0f; } double num8 = 0.0; for (int i = 0; i < 512; i++) { float num9 = ((Il2CppArrayBase)(object)_samples)[i]; if (float.IsFinite(num9)) { num8 += (double)(num9 * num9); } } return Mathf.Clamp01((float)Math.Sqrt(num8 / 512.0)); } catch (Exception ex) { ReleaseMicrophone(); Status = "Microphone unavailable; retrying"; _nextAttempt = now + 5f; WarnOnce("Microphone input failed: " + ex.GetBaseException().Message); return 0f; } } private void ReleaseMicrophone() { if (_ownsRecording) { _ownsRecording = false; try { if (Microphone.IsRecording(_device)) { Microphone.End(_device); } } catch (Exception ex) { WarnOnce("Could not release echolocation microphone: " + ex.GetBaseException().Message); } } if ((Object)(object)_clip != (Object)null && Object.op_Implicit((Object)(object)_clip)) { Object.Destroy((Object)(object)_clip); _clip = null; } _lastPosition = -1; _capturedFrames = 0; } private void WarnOnce(string message) { if (!(_lastWarning == message)) { _lastWarning = message; _warning(message); } } public void Dispose() { if (!_disposed) { _disposed = true; ReleaseMicrophone(); _samples = null; _fusion.Reset(); } } } internal class SoundEmitterSurface { internal const int MaximumColliders = 256; private readonly Dictionary _colliders; private readonly Collider[] _ordered; internal Vector3? Origin { get; } internal int Count => _ordered.Length; internal SoundEmitterSurface(Collider[] colliders, Vector3? origin = null) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0059: 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) if (colliders == null) { throw new ArgumentNullException("colliders"); } if (colliders.Length > 256) { throw new ArgumentException("Sound-emitter collider snapshot exceeds its bounded capacity.", "colliders"); } if (origin.HasValue) { Vector3 valueOrDefault = origin.GetValueOrDefault(); if (float.IsFinite(valueOrDefault.x) && float.IsFinite(valueOrDefault.y) && float.IsFinite(valueOrDefault.z)) { Origin = valueOrDefault; } } _colliders = new Dictionary(colliders.Length); foreach (Collider val in colliders) { if ((Object)(object)val != (Object)null) { _colliders[((Object)val).GetInstanceID()] = val; } } _ordered = (Collider[])(object)new Collider[_colliders.Count]; _colliders.Values.CopyTo(_ordered, 0); } internal Collider GetCollider(int index) { return _ordered[index]; } internal bool IsOwnCollider(Collider collider) { if ((Object)(object)collider != (Object)null && _colliders.TryGetValue(((Object)collider).GetInstanceID(), out Collider value) && (Object)(object)value != (Object)null) { return (Object)(object)value == (Object)(object)collider; } return false; } } internal sealed class NpcSoundEmission : SoundEmitterSurface { internal NpcSoundEmission(Collider[] colliders) : base(colliders) { } } internal sealed class NpcSoundSources { private const int MaximumBrains = 128; private const int MaximumMuscles = 128; private readonly Action _warning; private readonly List _brains = new List(128); private float _nextDiscovery; private float _nextWarning; private bool _discoveryComplete; internal NpcSoundSources(Action warning) { _warning = warning; } internal NpcSoundEmission? Capture(float now, AudioSource source) { if (!float.IsFinite(now) || (Object)(object)source == (Object)null || !((Behaviour)source).isActiveAndEnabled) { return null; } try { Refresh(now); if (!_discoveryComplete) { return null; } PuppetMaster owner = null; AIBrain componentInParent = ((Component)source).GetComponentInParent(); PuppetMaster componentInParent2 = ((Component)source).GetComponentInParent(); BehaviourBase componentInParent3 = ((Component)source).GetComponentInParent(); if (!MergeOwner(ref owner, ((Object)(object)componentInParent != (Object)null) ? componentInParent.puppetMaster : null) || !MergeOwner(ref owner, componentInParent2) || !MergeOwner(ref owner, ((Object)(object)componentInParent3 != (Object)null) ? componentInParent3.puppetMaster : null)) { return null; } foreach (AIBrain brain in _brains) { if ((Object)(object)brain == (Object)null || !((Component)brain).gameObject.activeInHierarchy) { continue; } BehaviourBaseNav behaviour = brain.behaviour; if ((Object)(object)behaviour == (Object)null) { continue; } SubBehaviourSfx sfx = behaviour.sfx; if (sfx != null && Matches(sfx, source)) { PuppetMaster puppetMaster = brain.puppetMaster; if ((Object)(object)puppetMaster == (Object)null || !((Component)puppetMaster).gameObject.activeInHierarchy || !MergeOwner(ref owner, puppetMaster)) { return null; } } } return ((Object)(object)owner != (Object)null) ? Snapshot(owner) : null; } catch (Exception ex) { if (now >= _nextWarning) { _nextWarning = now + 10f; _warning("NPC sound ownership was unavailable: " + ex.GetType().Name); } return null; } } private void Refresh(float now) { if (now < _nextDiscovery) { return; } _nextDiscovery = now + 1f; _brains.Clear(); _discoveryComplete = false; Il2CppArrayBase val = Object.FindObjectsOfType(); if (val.Length > 128) { return; } for (int i = 0; i < val.Length; i++) { AIBrain val2 = val[i]; if ((Object)(object)val2 != (Object)null && ((Component)val2).gameObject.activeInHierarchy) { _brains.Add(val2); } } _discoveryComplete = true; } private static bool MergeOwner(ref PuppetMaster? owner, PuppetMaster? candidate) { if ((Object)(object)candidate == (Object)null) { return true; } if (!((Component)candidate).gameObject.activeInHierarchy) { return false; } if ((Object)(object)owner != (Object)null && (Object)(object)owner != (Object)(object)candidate) { return false; } owner = candidate; return true; } private static bool Matches(SubBehaviourSfx sfx, AudioSource source) { if (!Same(sfx._mouthSource, source) && !Same(sfx.impactSource, source) && !Same(sfx._loopSource, source) && !Same(ManagedSource(sfx._mapMovement), source)) { return Same(ManagedSource(sfx._mapDotLoop), source); } return true; } private static bool Same(AudioSource? candidate, AudioSource source) { if ((Object)(object)candidate != (Object)null) { return (Object)(object)candidate == (Object)(object)source; } return false; } private static AudioSource? ManagedSource(ManagedAudioPlayer? player) { if (player == null) { return null; } AudioPlayer ap = player._ap; if (!((Object)(object)ap != (Object)null) || ((SpawnEvents)ap).IsDespawned || player._Id != ((SpawnEvents)ap).ID) { return null; } return ap.source; } private static NpcSoundEmission? Snapshot(PuppetMaster owner) { Il2CppReferenceArray muscles = owner.muscles; if (muscles == null || ((Il2CppArrayBase)(object)muscles).Length == 0 || ((Il2CppArrayBase)(object)muscles).Length > 128) { return null; } List list = new List(); for (int i = 0; i < ((Il2CppArrayBase)(object)muscles).Length; i++) { Muscle val = ((Il2CppArrayBase)(object)muscles)[i]; if (val == null) { continue; } Il2CppReferenceArray colliders = val.colliders; if (colliders != null) { if (((Il2CppArrayBase)(object)colliders).Length > 256 - list.Count) { return null; } for (int j = 0; j < ((Il2CppArrayBase)(object)colliders).Length; j++) { list.Add(((Il2CppArrayBase)(object)colliders)[j]); } } } if (list.Count != 0) { return new NpcSoundEmission(list.ToArray()); } return null; } internal void Reset() { _brains.Clear(); _nextDiscovery = 0f; _nextWarning = 0f; _discoveryComplete = false; } } internal sealed class ObjectSoundSources { private const int MaximumComponents = 512; private const int MaximumColliders = 256; private readonly Action _warning; private readonly List _impacts = new List(512); private readonly List _collisions = new List(512); private readonly List _guns = new List(512); private float _nextDiscovery; private float _nextWarning; private bool _discoveryComplete; internal ObjectSoundSources(Action warning) { _warning = warning; } internal SoundEmitterSurface? Capture(float now, AudioSource source) { //IL_0263: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Unknown result type (might be due to invalid IL or missing references) if (!float.IsFinite(now) || (Object)(object)source == (Object)null || !((Behaviour)source).isActiveAndEnabled) { return null; } try { Refresh(now); if (!_discoveryComplete) { return null; } Rigidbody owner = null; foreach (ImpactSFX impact in _impacts) { if (!((Object)(object)impact == (Object)null) && ((Behaviour)impact).isActiveAndEnabled && Matches(impact._mapImpact, source)) { Rigidbody val = impact._rb; if ((Object)(object)val == (Object)null) { val = ((Component)impact).GetComponent(); } if (!MergeOwner(ref owner, val)) { return null; } } } foreach (CollisionSFX collision in _collisions) { if (!((Object)(object)collision == (Object)null) && ((Behaviour)collision).isActiveAndEnabled && (Matches(collision._mapImpact, source) || Matches(collision._mapSlide, source))) { Rigidbody val2 = collision._body; if ((Object)(object)val2 == (Object)null) { val2 = ((Component)collision).GetComponent(); } if (!MergeOwner(ref owner, val2)) { return null; } } } Gun val3 = null; Vector3? origin = null; foreach (Gun gun in _guns) { if ((Object)(object)gun == (Object)null || !((Behaviour)gun).isActiveAndEnabled) { continue; } GunSFX gunSFX = gun.gunSFX; if (!((Object)(object)gunSFX == (Object)null) && ((Behaviour)gunSFX).isActiveAndEnabled && Matches(gunSFX._gunshotMap, source)) { if ((Object)(object)val3 != (Object)null && (Object)(object)val3 != (Object)(object)gun) { return null; } val3 = gun; Rigidbody val4 = (((Object)(object)gun.host != (Object)null) ? gun.host.Rb : null); if ((Object)(object)val4 == (Object)null && (Object)(object)gunSFX._host != (Object)null) { val4 = gunSFX._host.Rb; } if ((Object)(object)val4 == (Object)null) { val4 = ((Component)gun).GetComponent(); } if (!MergeOwner(ref owner, val4)) { return null; } Transform firePointTransform = gun.firePointTransform; Vector3 value = (((Object)(object)firePointTransform != (Object)null) ? firePointTransform.position : ((Component)gun).transform.position); if (!Finite(value)) { value = ((Component)gun).transform.position; } if (Finite(value)) { origin = value; } } } return ((Object)(object)owner != (Object)null) ? Snapshot(owner, origin) : null; } catch (Exception ex) { if (now >= _nextWarning) { _nextWarning = now + 10f; _warning("Object sound ownership was unavailable: " + ex.GetType().Name); } return null; } } private void Refresh(float now) { if (now < _nextDiscovery) { return; } _nextDiscovery = now + 1f; _discoveryComplete = false; _impacts.Clear(); _collisions.Clear(); _guns.Clear(); Il2CppArrayBase val = Object.FindObjectsOfType(); Il2CppArrayBase val2 = Object.FindObjectsOfType(); Il2CppArrayBase val3 = Object.FindObjectsOfType(); if (val.Length > 512 || val2.Length > 512 - val.Length || val3.Length > 512 - val.Length - val2.Length) { return; } for (int i = 0; i < val.Length; i++) { if ((Object)(object)val[i] != (Object)null) { _impacts.Add(val[i]); } } for (int j = 0; j < val2.Length; j++) { if ((Object)(object)val2[j] != (Object)null) { _collisions.Add(val2[j]); } } for (int k = 0; k < val3.Length; k++) { if ((Object)(object)val3[k] != (Object)null) { _guns.Add(val3[k]); } } _discoveryComplete = true; } private static bool Matches(ManagedAudioPlayer? managed, AudioSource source) { if (managed == null) { return false; } AudioPlayer ap = managed._ap; if ((Object)(object)ap != (Object)null && !((SpawnEvents)ap).IsDespawned && managed._Id == ((SpawnEvents)ap).ID && (Object)(object)ap.source != (Object)null) { return (Object)(object)ap.source == (Object)(object)source; } return false; } private static bool MergeOwner(ref Rigidbody? owner, Rigidbody candidate) { if ((Object)(object)candidate == (Object)null || !((Component)candidate).gameObject.activeInHierarchy) { return false; } if ((Object)(object)owner != (Object)null && (Object)(object)owner != (Object)(object)candidate) { return false; } owner = candidate; return true; } 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 SoundEmitterSurface? Snapshot(Rigidbody owner, Vector3? origin) { Il2CppArrayBase componentsInChildren = ((Component)owner).GetComponentsInChildren(true); if (componentsInChildren == null || componentsInChildren.Length == 0 || componentsInChildren.Length > 256) { return null; } List list = new List(componentsInChildren.Length); for (int i = 0; i < componentsInChildren.Length; i++) { Collider val = componentsInChildren[i]; if ((Object)(object)val != (Object)null && (Object)(object)val.attachedRigidbody == (Object)(object)owner && !val.isTrigger) { list.Add(val); } } if (list.Count != 0) { return new SoundEmitterSurface(list.ToArray(), origin); } return null; } internal void Reset() { _impacts.Clear(); _collisions.Clear(); _guns.Clear(); _nextDiscovery = 0f; _nextWarning = 0f; _discoveryComplete = false; } } internal sealed class PlayerEchoes : IDisposable { private sealed class State { internal PlayerTarget Target; internal readonly EchoReveal Reveal = new EchoReveal(); internal bool Visible; internal float NextRay; } private readonly Settings _settings; private readonly PlayerTargets _targets; private readonly PlayerEchoRenderer _renderer; private readonly VisibilityRaycaster _rays = new VisibilityRaycaster(); private readonly Dictionary _states = new Dictionary(); private readonly List _removed = new List(); private int _first; private bool _wasEnabled = true; internal string Status => $"{_targets.Status}; silhouette renderer ready={_renderer.Ready}"; internal PlayerEchoes(Settings settings, Action warning) { _settings = settings; _targets = new PlayerTargets(warning); _renderer = new PlayerEchoRenderer(warning); } internal void PrepareTargets(float now, Transform? localRoot) { _targets.Refresh(now, localRoot); } internal bool IsPlayerTransform(Transform transform) { return _targets.ContainsPlayerTransform(transform); } internal void ObserveSound(EchoEvent echo, Transform? localRoot) { if (!_settings.PlayerHighlights || echo.Strength <= 0f || !float.IsFinite(echo.Time)) { return; } _targets.Refresh(echo.Time, localRoot); PlayerTarget playerTarget = _targets.FindSoundOwner(echo); if (playerTarget != null && playerTarget.Alive) { int instanceID = ((Object)playerTarget.Root).GetInstanceID(); if (!_states.TryGetValue(instanceID, out State value) || value.Target != playerTarget) { value = new State { Target = playerTarget }; _states[instanceID] = value; } value.Reveal.Schedule(echo.Time, 0.5f, Mathf.Lerp(0.5f, 1f, echo.Strength)); } } internal void Tick(float now, Transform head, Transform? localRoot) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0133: 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) if (!_settings.PlayerHighlights) { if (_wasEnabled) { _states.Clear(); _renderer.Reset(); } _wasEnabled = false; return; } _wasEnabled = true; _targets.Refresh(now, localRoot); _renderer.BeginFrame(now); Vector3 val = EyePosition(head); IReadOnlyList targets = _targets.Targets; if (targets.Count > 0) { _first = (_first + 1) % targets.Count; for (int i = 0; i < targets.Count; i++) { PlayerTarget playerTarget = targets[(_first + i) % targets.Count]; if (!playerTarget.Alive || !_states.TryGetValue(((Object)playerTarget.Root).GetInstanceID(), out State value) || value.Target != playerTarget) { continue; } float num = value.Reveal.Opacity(now); if (!(num < 0.01f) && !(Vector3.Distance(val, playerTarget.ChestPosition) > _settings.WorldRange)) { if (now >= value.NextRay) { value.NextRay = now + 0.1f; value.Visible = _rays.CanSee(val, localRoot, playerTarget.Root, playerTarget.HeadPosition, playerTarget.ChestPosition); } _renderer.Draw(now, playerTarget, value.Visible, num); } } } _removed.Clear(); foreach (KeyValuePair state in _states) { if (!state.Value.Target.Alive || !Contains(targets, state.Value.Target)) { _removed.Add(state.Key); } } foreach (int item in _removed) { _states.Remove(item); } } private static bool Contains(IReadOnlyList targets, PlayerTarget target) { foreach (PlayerTarget target2 in targets) { if (target2 == target) { return true; } } return false; } private static Vector3 EyePosition(Transform fallback) { //IL_007d: 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_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_0083: Unknown result type (might be due to invalid IL or missing references) OpenControllerRig controllerRig = Player.ControllerRig; if ((Object)(object)controllerRig != (Object)null && controllerRig.cameras != null) { foreach (Camera item in (Il2CppArrayBase)(object)controllerRig.cameras) { if ((Object)(object)item != (Object)null && ((Behaviour)item).isActiveAndEnabled) { return ((Component)item).transform.position; } } } if (!((Object)(object)Camera.main != (Object)null)) { return fallback.position; } return ((Component)Camera.main).transform.position; } internal void Reset() { _states.Clear(); _targets.Reset(); _renderer.Reset(); _first = 0; } public void Dispose() { Reset(); _renderer.Dispose(); } } internal sealed class PlayerEchoRenderer : IDisposable { private sealed class CachedMesh { internal Renderer Renderer; internal Mesh Source; internal Mesh Mesh; internal Il2CppStructArray? White; internal float NextBake; internal float LastSeen; } private readonly Dictionary _meshes = new Dictionary(); private readonly List _expired = new List(); private readonly Action _warning; private Material? _material; private MaterialPropertyBlock? _block; private int _bakes; private int _draws; private int _attempts; private float _now; private float _nextAttempt; private float _nextCleanup; private float _nextWarning; private bool _disposed; internal bool Ready { get { if (!_disposed) { return (Object)(object)_material != (Object)null; } return false; } } internal PlayerEchoRenderer(Action warning) { _warning = warning; } internal void BeginFrame(float now) { _now = now; _bakes = 4; _draws = 128; if (_disposed) { return; } EnsureMaterial(); if (now < _nextCleanup) { return; } _nextCleanup = now + 0.5f; _expired.Clear(); foreach (KeyValuePair mesh in _meshes) { if ((Object)(object)mesh.Value.Renderer == (Object)null || now - mesh.Value.LastSeen > 2f) { _expired.Add(mesh.Key); } } foreach (int item in _expired) { Remove(item); } } internal void Draw(float now, PlayerTarget target, bool visible, float alpha) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Expected O, but got Unknown //IL_02d7: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) if (_disposed || (Object)(object)_material == (Object)null || !target.Alive || alpha < 0.01f) { return; } Color val = (visible ? new Color(0.08f, 1f, 0.18f, alpha * 0.85f) : new Color(1f, 0.06f, 0.03f, alpha * 0.85f)); _block.Clear(); _block.SetColor("_Color", val); for (int i = 0; i < target.Renderers.Length && i < 8; i++) { if (_draws <= 0) { break; } Renderer val2 = target.Renderers[i]; if ((Object)(object)val2 == (Object)null || !val2.enabled || !((Component)val2).gameObject.activeInHierarchy) { continue; } try { SkinnedMeshRenderer val3 = ((Il2CppObjectBase)val2).TryCast(); object obj; if (!((Object)(object)val3 != (Object)null)) { MeshFilter component = ((Component)val2).GetComponent(); obj = ((component != null) ? component.sharedMesh : null); } else { obj = val3.sharedMesh; } Mesh val4 = (Mesh)obj; if ((Object)(object)val4 == (Object)null || val4.vertexCount == 0 || val4.vertexCount > 120000) { continue; } int instanceID = ((Object)val2).GetInstanceID(); if (_meshes.TryGetValue(instanceID, out CachedMesh value) && ((Object)(object)value.Renderer != (Object)(object)val2 || (Object)(object)value.Source != (Object)(object)val4)) { Remove(instanceID); value = null; } if (value != null) { goto IL_01bc; } if (_bakes <= 0) { continue; } if (_meshes.Count >= 128) { EvictOldest(); } value = new CachedMesh { Renderer = val2, Source = val4, Mesh = new Mesh { name = "Echolocation.PlayerEcho", hideFlags = (HideFlags)61 } }; _meshes[instanceID] = value; goto IL_01bc; IL_01bc: value.LastSeen = now; if (now >= value.NextBake && _bakes > 0) { _bakes--; if ((Object)(object)val3 != (Object)null) { val3.BakeMesh(value.Mesh, false); } else { Object.Destroy((Object)(object)value.Mesh); value.Mesh = Object.Instantiate(val4); ((Object)value.Mesh).hideFlags = (HideFlags)61; } int vertexCount = value.Mesh.vertexCount; if (value.White == null || ((Il2CppArrayBase)(object)value.White).Length != vertexCount) { value.White = new Il2CppStructArray((long)vertexCount); for (int j = 0; j < vertexCount; j++) { ((Il2CppArrayBase)(object)value.White)[j] = Color.white; } } value.Mesh.SetColors(value.White); value.NextBake = (((Object)(object)val3 != (Object)null) ? (now + 0.1f) : float.PositiveInfinity); } if (value.Mesh.vertexCount == 0) { continue; } for (int k = 0; k < Math.Min(value.Mesh.subMeshCount, 8); k++) { if (_draws <= 0) { break; } Graphics.DrawMesh(value.Mesh, val2.localToWorldMatrix, _material, 0, (Camera)null, k, _block, (ShadowCastingMode)0, false, (Transform)null, (LightProbeUsage)0, (LightProbeProxyVolume)null); _draws--; } } catch (Exception ex) { if (now >= _nextWarning) { _nextWarning = now + 10f; _warning("Player echo mesh: " + ex.Message); } } } } private void EnsureMaterial() { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Expected O, but got Unknown //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Expected O, but got Unknown if ((Object)(object)_material != (Object)null || _attempts >= 6 || _now < _nextAttempt) { return; } _attempts++; _nextAttempt = _now + 2f; 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 = 5000 }; if (text == "Hidden/Internal-Colored" && (!val2.HasProperty("_ZTest") || !val2.HasProperty("_ZWrite"))) { Object.Destroy((Object)(object)val2); continue; } if (val2.HasProperty("_Color")) { val2.SetColor("_Color", Color.white); } if (val2.HasProperty("_MainTex")) { val2.SetTexture("_MainTex", (Texture)(object)Texture2D.whiteTexture); } Set(val2, "_ZTest", 8); Set(val2, "_ZWrite", 0); Set(val2, "_Cull", 0); Set(val2, "_SrcBlend", 5); Set(val2, "_DstBlend", 10); _material = val2; _block = new MaterialPropertyBlock(); return; } if (_attempts == 1 || _attempts == 6) { _warning("Player echo highlight shader unavailable."); } } private void EvictOldest() { int key = 0; float num = float.PositiveInfinity; foreach (KeyValuePair mesh in _meshes) { if (mesh.Value.LastSeen < num) { num = mesh.Value.LastSeen; key = mesh.Key; } } Remove(key); } private void Remove(int key) { if (_meshes.TryGetValue(key, out CachedMesh value)) { if ((Object)(object)value.Mesh != (Object)null) { Object.Destroy((Object)(object)value.Mesh); } _meshes.Remove(key); } } internal void Reset() { foreach (CachedMesh value in _meshes.Values) { if ((Object)(object)value.Mesh != (Object)null) { Object.Destroy((Object)(object)value.Mesh); } } _meshes.Clear(); _attempts = 0; _nextAttempt = 0f; _nextCleanup = 0f; } public void Dispose() { if (!_disposed) { _disposed = true; Reset(); if ((Object)(object)_material != (Object)null) { Object.Destroy((Object)(object)_material); } _material = null; _block = null; } } private static void Set(Material material, string name, int value) { if (material.HasProperty(name)) { material.SetInt(name, value); } } } internal sealed class PlayerTarget { internal Transform Root; internal Transform AvatarRoot; internal Transform? Head; internal int FusionPlayerId = -1; internal FootstepSFX[] Footsteps = Array.Empty(); internal Renderer[] Renderers = Array.Empty(); internal bool Alive { get { if ((Object)(object)Root != (Object)null && (Object)(object)AvatarRoot != (Object)null) { return ((Component)Root).gameObject.activeInHierarchy; } return false; } } internal Vector3 ChestPosition { get { //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_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0072: 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_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) Renderer val = null; float num = 0f; Renderer[] renderers = Renderers; Bounds bounds; foreach (Renderer val2 in renderers) { if (!((Object)(object)val2 == (Object)null)) { bounds = val2.bounds; Vector3 size = ((Bounds)(ref bounds)).size; float sqrMagnitude = ((Vector3)(ref size)).sqrMagnitude; if (sqrMagnitude > num) { num = sqrMagnitude; val = val2; } } } if (!((Object)(object)val != (Object)null)) { return Root.position + Vector3.up; } bounds = val.bounds; return ((Bounds)(ref bounds)).center; } } internal Vector3 HeadPosition { get { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Head != (Object)null)) { return ChestPosition + Vector3.up * 0.5f; } return Head.position; } } } internal sealed class PlayerTargets { private readonly Action _warning; private readonly List _targets = new List(32); private readonly Dictionary _cache = new Dictionary(); private readonly HashSet _seen = new HashSet(); private readonly List _removed = new List(); private FieldInfo? _players; private PropertyInfo? _id; private PropertyInfo? _smallId; private PropertyInfo? _isMe; private PropertyInfo? _validId; private PropertyInfo? _hasRig; private PropertyInfo? _forceHide; private PropertyInfo? _refs; private PropertyInfo? _rigManager; private PropertyInfo? _head; private float _nextRefresh; private float _nextWarning; internal IReadOnlyList Targets => _targets; internal string Status { get; private set; } = "Waiting for Fusion players"; internal PlayerTargets(Action warning) { _warning = warning; } internal void Refresh(float now, Transform? localRoot) { if (now < _nextRefresh) { return; } _nextRefresh = now + 0.5f; _targets.Clear(); _seen.Clear(); try { if (_players == null) { Bind(); } if (!(_players?.GetValue(null) is IEnumerable enumerable)) { return; } int num = 0; foreach (object item in enumerable) { if (++num > 128 || _targets.Count >= 32) { break; } try { object value = _id.GetValue(item); if (value == null) { continue; } object value2 = _isMe.GetValue(value); if (value2 is bool && (bool)value2) { continue; } value2 = _validId.GetValue(value); if (!(value2 is bool) || !(bool)value2) { continue; } value2 = _hasRig.GetValue(item); if (!(value2 is bool) || !(bool)value2) { continue; } value2 = _forceHide.GetValue(item); if (value2 is bool && (bool)value2) { continue; } object value3 = _refs.GetValue(item); if (value3 == null) { continue; } object? value4 = _rigManager.GetValue(value3); RigManager val = (RigManager)((value4 is RigManager) ? value4 : null); if (val == null || (Object)(object)val == (Object)null || (Object)(object)val.avatar == (Object)null) { continue; } Transform transform = ((Component)val).transform; if ((Object)(object)transform == (Object)(object)localRoot || ((Object)(object)localRoot != (Object)null && transform.IsChildOf(localRoot))) { continue; } Transform transform2 = ((Component)val.avatar).transform; int instanceID = ((Object)transform).GetInstanceID(); int num2 = Convert.ToInt32(_smallId.GetValue(value)); if (!_cache.TryGetValue(instanceID, out PlayerTarget value5) || (Object)(object)value5.AvatarRoot != (Object)(object)transform2 || value5.FusionPlayerId != num2) { value5 = new PlayerTarget { Root = transform, AvatarRoot = transform2, FusionPlayerId = num2 }; _cache[instanceID] = value5; } ref Transform? head = ref value5.Head; object? value6 = _head.GetValue(value3); head = (Transform?)((value6 is Transform) ? value6 : null); Il2CppArrayBase componentsInChildren = ((Component)transform).GetComponentsInChildren(false); List list = new List(Math.Min(16, componentsInChildren.Length)); for (int i = 0; i < Math.Min(32, componentsInChildren.Length); i++) { if ((Object)(object)componentsInChildren[i] != (Object)null) { list.Add(componentsInChildren[i]); } } value5.Footsteps = list.ToArray(); Il2CppArrayBase componentsInChildren2 = ((Component)transform2).GetComponentsInChildren(false); List list2 = new List(Math.Min(16, componentsInChildren2.Length)); foreach (Renderer item2 in componentsInChildren2) { if (!((Object)(object)((Il2CppObjectBase)item2).TryCast() == (Object)null) || !((Object)(object)((Il2CppObjectBase)item2).TryCast() == (Object)null)) { list2.Add(item2); if (list2.Count == 128) { break; } } } list2.Sort(delegate(Renderer a, Renderer b) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) Bounds bounds = b.bounds; Vector3 size = ((Bounds)(ref bounds)).size; float sqrMagnitude = ((Vector3)(ref size)).sqrMagnitude; bounds = a.bounds; size = ((Bounds)(ref bounds)).size; return sqrMagnitude.CompareTo(((Vector3)(ref size)).sqrMagnitude); }); if (list2.Count > 16) { list2.RemoveRange(16, list2.Count - 16); } value5.Renderers = list2.ToArray(); if (value5.Alive) { _seen.Add(instanceID); _targets.Add(value5); } } catch (Exception ex) { if (now >= _nextWarning) { _nextWarning = now + 10f; _warning("Player rig unavailable during refresh: " + ex.GetBaseException().Message); } } } Status = $"Tracking {_targets.Count} remote Fusion players"; } catch (Exception ex2) { _targets.Clear(); Status = "Fusion player tracking unavailable"; if (now >= _nextWarning) { _nextWarning = now + 10f; _warning(Status + ": " + ex2.GetBaseException().Message); } } _removed.Clear(); foreach (int key in _cache.Keys) { if (!_seen.Contains(key)) { _removed.Add(key); } } foreach (int item3 in _removed) { _cache.Remove(item3); } } internal PlayerTarget? FindSoundOwner(EchoEvent echo) { if (echo.Kind != EchoKind.Voice && echo.Kind != EchoKind.World) { return null; } if (echo.Kind == EchoKind.Voice && (echo.PlayerId < 0 || echo.PlayerId > 255)) { return null; } AudioSource source = echo.Source; if (echo.Kind == EchoKind.World && (Object)(object)source == (Object)null) { return null; } PlayerTarget playerTarget = null; foreach (PlayerTarget target in _targets) { try { if (target.Alive && ((echo.Kind == EchoKind.Voice) ? (target.FusionPlayerId == echo.PlayerId) : OwnsSource(target, source))) { if (playerTarget != null && playerTarget != target) { return null; } playerTarget = target; } } catch (Exception) { return null; } } return playerTarget; } private static bool OwnsSource(PlayerTarget target, AudioSource source) { if ((Object)(object)source == (Object)null) { return false; } if (UnderRoot(((Component)source).transform, target.Root)) { return true; } FootstepSFX[] footsteps = target.Footsteps; foreach (FootstepSFX val in footsteps) { if ((Object)(object)val != (Object)null && ((Behaviour)val).isActiveAndEnabled && UnderRoot(((Component)val).transform, target.Root) && (Object)(object)val.source == (Object)(object)source) { return true; } } return false; } internal bool ContainsPlayerTransform(Transform transform) { if ((Object)(object)transform == (Object)null) { return false; } foreach (PlayerTarget target in _targets) { try { if (target.Alive && UnderRoot(transform, target.Root)) { return true; } } catch (Exception) { } } return (Object)(object)((Component)transform).GetComponentInParent() != (Object)null; } private static bool UnderRoot(Transform transform, Transform root) { if ((Object)(object)transform != (Object)null && (Object)(object)root != (Object)null) { if (!((Object)(object)transform == (Object)(object)root)) { return transform.IsChildOf(root); } return true; } return false; } private void Bind() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (!(assembly.GetName().Name != "LabFusion")) { Type type = assembly.GetType("LabFusion.Entities.NetworkPlayer", throwOnError: true); Type type2 = assembly.GetType("LabFusion.Player.PlayerID", throwOnError: true); Type type3 = assembly.GetType("LabFusion.Entities.RigRefs", throwOnError: true); _id = Property(type, "PlayerID"); _smallId = Property(type2, "SmallID"); _isMe = Property(type2, "IsMe"); _validId = Property(type2, "IsValid"); _hasRig = Property(type, "HasRig"); _forceHide = Property(type, "ForceHide"); _refs = Property(type, "RigRefs"); _rigManager = Property(type3, "RigManager"); _head = Property(type3, "Head"); FieldInfo? field = type.GetField("Players", BindingFlags.Static | BindingFlags.Public); if ((object)field == null) { throw new MissingFieldException(type.FullName, "Players"); } _players = field; break; } } } private static PropertyInfo Property(Type type, string name) { return type.GetProperty(name) ?? throw new MissingMemberException(type.FullName, name); } internal void Reset() { _targets.Clear(); _cache.Clear(); _seen.Clear(); _removed.Clear(); _nextRefresh = 0f; } } internal sealed class PulseAudio : IDisposable { private const int SampleRate = 44100; private readonly Action _warning; private GameObject? _object; private AudioSource? _source; private AudioClip? _clap; private AudioClip? _pulse; private string? _lastWarning; private bool _disposed; internal string Status { get; private set; } = "Ready for clap feedback"; internal PulseAudio(Action warning) { _warning = warning; } internal void PlayClap(float volume) { Play(pulse: false, volume); } internal void PlayPulse(float volume) { Play(pulse: true, volume); } private void Play(bool pulse, float volume) { if (_disposed || !float.IsFinite(volume) || volume <= 0f) { return; } try { EnsureAssets(); _source.PlayOneShot(pulse ? _pulse : _clap, Math.Min(volume, 1f)); Status = (pulse ? "Sonar chirp played" : "First clap accepted"); _lastWarning = null; } catch (Exception ex) { Status = "Clap feedback unavailable"; string text = "Clap feedback unavailable: " + ex.Message; if (text != _lastWarning) { _lastWarning = text; _warning(text); } } } private void EnsureAssets() { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown if ((Object)(object)_clap == (Object)null) { _clap = CreateClip("Echolocation.Clap", pulse: false); } if ((Object)(object)_pulse == (Object)null) { _pulse = CreateClip("Echolocation.Sonar", pulse: true); } if (!((Object)(object)_source != (Object)null) || !((Object)(object)_object != (Object)null)) { DestroyOwned((Object?)(object)_object); _object = new GameObject("Echolocation.PulseAudio"); ((Object)_object).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)_object); _source = _object.AddComponent(); if ((Object)(object)_source == (Object)null) { throw new InvalidOperationException("Could not create the audio source."); } _source.playOnAwake = false; _source.loop = false; _source.spatialBlend = 0f; _source.dopplerLevel = 0f; _source.priority = 32; _source.volume = 1f; _source.mute = false; _source.ignoreListenerPause = true; } } private static AudioClip CreateClip(string name, bool pulse) { int num = (int)(44100f * (pulse ? 0.35f : 0.055f)); AudioClip val = AudioClip.Create(name, num, 1, 44100, false); if ((Object)(object)val == (Object)null) { throw new InvalidOperationException("Could not create a feedback clip."); } try { Il2CppStructArray val2 = new Il2CppStructArray((long)num); double num2 = ((double)num - 1.0) / 44100.0; double num3 = (pulse ? 1250.0 : 1800.0); double num4 = (pulse ? 430.0 : 1000.0); for (int i = 0; i < num; i++) { double num5 = (double)i / 44100.0; double num6 = num5 / num2; double num7 = Math.PI * 2.0 * (num3 * num5 + 0.5 * (num4 - num3) * num5 * num5 / num2); double num8 = Math.Sin(Math.Min(1.0, num5 / 0.006) * Math.PI * 0.5); double num9 = Math.Sin((1.0 - num6) * Math.PI * 0.5); double num10 = num8 * num8 * num9 * num9; double num11 = Math.Sin(num7) * 0.82 + Math.Sin(num7 * 2.0) * 0.18; ((Il2CppArrayBase)(object)val2)[i] = (float)(num11 * num10 * (pulse ? 0.65 : 0.34)); } if (!val.SetData(val2, 0)) { throw new InvalidOperationException("Unity rejected the feedback audio samples."); } return val; } catch { DestroyOwned((Object?)(object)val); throw; } } internal void Stop() { if (_disposed) { return; } try { if ((Object)(object)_source != (Object)null) { _source.Stop(); } } catch { } Status = "Ready for clap feedback"; } private static void DestroyOwned(Object? value) { try { if (value != (Object)null) { Object.Destroy(value); } } catch { } } public void Dispose() { if (!_disposed) { Stop(); _disposed = true; DestroyOwned((Object?)(object)_object); DestroyOwned((Object?)(object)_clap); DestroyOwned((Object?)(object)_pulse); _object = null; _source = null; _clap = null; _pulse = null; Status = "Clap feedback disposed"; } } } internal sealed class PulseGate { private float _lastFire = float.NegativeInfinity; public bool TryFire(float now, float level, float threshold, float cooldown) { if (!float.IsFinite(now) || !float.IsFinite(level) || !float.IsFinite(threshold) || !float.IsFinite(cooldown) || threshold <= 0f || level < threshold) { return false; } if (now < _lastFire) { _lastFire = float.NegativeInfinity; } if (now - _lastFire < Math.Max(0.05f, cooldown)) { return false; } _lastFire = now; return true; } public void Reset() { _lastFire = float.NegativeInfinity; } } internal sealed class Settings { private readonly MelonPreferences_Category _category; private readonly MelonPreferences_Entry _enabled; private readonly MelonPreferences_Entry _mic; private readonly MelonPreferences_Entry _steps; private readonly MelonPreferences_Entry _world; private readonly MelonPreferences_Entry _voice; private readonly MelonPreferences_Entry _loops; private readonly MelonPreferences_Entry _keys; private readonly MelonPreferences_Entry _blackout; private readonly MelonPreferences_Entry _players; private readonly MelonPreferences_Entry _doubleClap; private readonly MelonPreferences_Entry _pulseSound; private readonly MelonPreferences_Entry _optimizeAutomatic; private readonly MelonPreferences_Entry _range; private readonly MelonPreferences_Entry _life; private readonly MelonPreferences_Entry _size; private readonly MelonPreferences_Entry _micThreshold; private readonly MelonPreferences_Entry _micCooldown; private readonly MelonPreferences_Entry _worldRange; private readonly MelonPreferences_Entry _soundThreshold; private readonly MelonPreferences_Entry _soundCooldown; private readonly MelonPreferences_Entry _stepDistance; private readonly MelonPreferences_Entry _clapDistance; private readonly MelonPreferences_Entry _pulseVolume; private readonly MelonPreferences_Entry _rays; private readonly MelonPreferences_Entry _budget; private readonly MelonPreferences_Entry _dots; private readonly MelonPreferences_Entry _device; private readonly MelonPreferences_Entry _sources; public bool Enabled { get { return _enabled.Value; } set { _enabled.Value = value; } } public bool Blackout { get { return _blackout.Value; } set { _blackout.Value = value; } } public bool PlayerHighlights { get { return _players.Value; } set { _players.Value = value; } } public bool OptimizeAutomaticEchoes { get { return _optimizeAutomatic.Value; } set { _optimizeAutomatic.Value = value; } } public bool DoubleClapEnabled { get { return _doubleClap.Value; } set { _doubleClap.Value = value; } } public bool PulseSoundEnabled { get { return _pulseSound.Value; } set { _pulseSound.Value = value; } } public float ClapContactDistance { get { return Bound(_clapDistance.Value, 0.3f, 0.15f, 0.45f); } set { _clapDistance.Value = Bound(value, 0.3f, 0.15f, 0.45f); } } public float PulseSoundVolume { get { return Bound(_pulseVolume.Value, 0.65f, 0f, 1f); } set { _pulseVolume.Value = Bound(value, 0.65f, 0f, 1f); } } public bool MicrophoneEnabled { get { return _mic.Value; } set { _mic.Value = value; } } public bool FootstepsEnabled { get { return _steps.Value; } set { _steps.Value = value; } } public bool WorldSoundEnabled { get { return _world.Value; } set { _world.Value = value; } } public bool FusionVoiceEnabled { get { return _voice.Value; } set { _voice.Value = value; } } public bool IncludeLoopingAudio { get { return _loops.Value; } set { _loops.Value = value; } } public bool DesktopHotkeys { get { return _keys.Value; } set { _keys.Value = value; } } public float Range { get { return Bound(_range.Value, 24f, 4f, 200f); } set { _range.Value = Bound(value, 24f, 4f, 200f); } } public float DotLifetime { get { return Bound(_life.Value, 1.8f, 0.3f, 5f); } set { _life.Value = Bound(value, 1.8f, 0.3f, 5f); } } public float DotSize { get { return Bound(_size.Value, 0.045f, 0.002f, 0.2f); } set { _size.Value = Bound(value, 0.045f, 0.002f, 0.2f); } } public float MicThreshold { get { return Bound(_micThreshold.Value, 0.025f, 0.001f, 0.8f); } set { _micThreshold.Value = Bound(value, 0.025f, 0.001f, 0.8f); } } public float MicCooldown { get { return Bound(_micCooldown.Value, 0.3f, 0.15f, 2f); } set { _micCooldown.Value = Bound(value, 0.3f, 0.15f, 2f); } } public float WorldRange { get { return Bound(_worldRange.Value, 30f, 3f, 200f); } set { _worldRange.Value = Bound(value, 30f, 3f, 200f); } } public float SoundThreshold { get { return Bound(_soundThreshold.Value, 0.025f, 0.001f, 0.8f); } set { _soundThreshold.Value = Bound(value, 0.025f, 0.001f, 0.8f); } } public float SoundCooldown { get { return Bound(_soundCooldown.Value, 0.45f, 0.2f, 3f); } set { _soundCooldown.Value = Bound(value, 0.45f, 0.2f, 3f); } } public float StepDistance { get { return Bound(_stepDistance.Value, 0.7f, 0.25f, 2f); } set { _stepDistance.Value = Bound(value, 0.7f, 0.25f, 2f); } } public int RayCount { get { return Math.Clamp(_rays.Value, 128, 16384); } set { _rays.Value = Math.Clamp(value, 128, 16384); } } public int RaysPerFrame { get { return Math.Clamp(_budget.Value, 32, 4096); } set { _budget.Value = Math.Clamp(value, 32, 4096); } } public int MaxDots { get { return Math.Clamp(_dots.Value, 512, 65536); } set { _dots.Value = Math.Clamp(value, 512, 65536); } } public int MicrophoneDeviceIndex { get { return Math.Clamp(_device.Value, -1, 64); } set { _device.Value = Math.Clamp(value, -1, 64); } } public int SourcesPerTick { get { return Math.Clamp(_sources.Value, 4, 64); } set { _sources.Value = Math.Clamp(value, 4, 64); } } public Settings() { _category = MelonPreferences.CreateCategory("Echolocation"); _enabled = _category.CreateEntry("Enabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _blackout = _category.CreateEntry("Blackout", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _players = _category.CreateEntry("PlayerHighlights", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _optimizeAutomatic = _category.CreateEntry("OptimizeAutomaticEchoes", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _doubleClap = _category.CreateEntry("DoubleClapEnabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _pulseSound = _category.CreateEntry("PulseSoundEnabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _clapDistance = _category.CreateEntry("ClapContactDistance", 0.3f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _pulseVolume = _category.CreateEntry("PulseSoundVolume", 0.65f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _mic = _category.CreateEntry("MicrophoneEnabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _steps = _category.CreateEntry("FootstepsEnabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _world = _category.CreateEntry("WorldSoundEnabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _voice = _category.CreateEntry("FusionVoiceEnabled", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _loops = _category.CreateEntry("IncludeLoopingAudio", false, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _keys = _category.CreateEntry("DesktopHotkeys", true, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _range = _category.CreateEntry("Range", 24f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _life = _category.CreateEntry("DotLifetime", 1.8f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _size = _category.CreateEntry("DotSize", 0.045f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _micThreshold = _category.CreateEntry("MicThreshold", 0.025f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _micCooldown = _category.CreateEntry("MicCooldown", 0.3f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _worldRange = _category.CreateEntry("WorldRange", 30f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _soundThreshold = _category.CreateEntry("SoundThreshold", 0.025f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _soundCooldown = _category.CreateEntry("SoundCooldown", 0.45f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _stepDistance = _category.CreateEntry("StepDistance", 0.7f, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _rays = _category.CreateEntry("RayCount", 2048, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _budget = _category.CreateEntry("RaysPerFrame", 512, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _dots = _category.CreateEntry("MaxDots", 16000, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _device = _category.CreateEntry("MicrophoneDeviceIndex", -1, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); _sources = _category.CreateEntry("SourcesPerTick", 24, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); MelonPreferences_Entry val = _category.CreateEntry("VisualDefaultsRevision", 0, (string)null, (string)null, false, false, (ValueValidator)null, (string)null); if (val.Value < 1) { if (_rays.Value == 640) { _rays.Value = 2048; } if (_budget.Value == 128) { _budget.Value = 512; } if (_dots.Value == 6000) { _dots.Value = 16000; } val.Value = 1; } } public void Save() { _category.SaveToFile(false); } private static float Bound(float value, float fallback, float min, float max) { return Math.Clamp(float.IsFinite(value) ? value : fallback, min, max); } } internal sealed class VisibilityRaycaster { private readonly Il2CppStructArray _hits = new Il2CppStructArray(64L); internal bool CanSee(Vector3 eye, Transform? localRoot, Transform targetRoot, Vector3 head, Vector3 chest) { //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) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (!ClearPath(eye, head, localRoot, targetRoot)) { return ClearPath(eye, chest, localRoot, targetRoot); } return true; } internal bool ClearPath(Vector3 origin, Vector3 endpoint, Transform? localRoot, Transform targetRoot) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_003e: 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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0079: 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) if (!Finite(origin) || !Finite(endpoint) || (Object)(object)targetRoot == (Object)null) { return false; } Vector3 val = endpoint - origin; float magnitude = ((Vector3)(ref val)).magnitude; if (magnitude <= 0.02f) { return true; } float num = magnitude - 0.01f; int num2 = Physics.RaycastNonAlloc(origin, val * (1f / magnitude), _hits, num, -5, (QueryTriggerInteraction)1); if (num2 >= ((Il2CppArrayBase)(object)_hits).Length) { return false; } for (int i = 0; i < num2; i++) { RaycastHit val2 = ((Il2CppArrayBase)(object)_hits)[i]; if (!((Object)(object)((RaycastHit)(ref val2)).collider == (Object)null) && !(((RaycastHit)(ref val2)).distance < 0f) && !(((RaycastHit)(ref val2)).distance > num)) { Transform transform = ((Component)((RaycastHit)(ref val2)).collider).transform; if (!BelongsTo(transform, localRoot) && !BelongsTo(transform, targetRoot)) { return false; } } } return true; } private static bool BelongsTo(Transform transform, Transform? root) { if ((Object)(object)root != (Object)null) { if (!((Object)(object)transform == (Object)(object)root)) { return transform.IsChildOf(root); } return true; } return false; } private static bool Finite(Vector3 value) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (float.IsFinite(value.x) && float.IsFinite(value.y)) { return float.IsFinite(value.z); } return false; } } internal sealed class WorldAudioMonitor : IDisposable { private sealed class PlaybackState { internal readonly AudioPlayer Player; internal AudioSource? Source; internal AudioClip? Clip; internal ulong Generation; internal int Samples; internal bool WasPlaying; internal PlaybackState(AudioPlayer player) { Player = player; } } private const int MaximumPlayers = 512; private const int PlayersPerFrame = 64; private const float DiscoveryInterval = 0.5f; private readonly Action _registerPlayingSource; private readonly Action _warning; private readonly List _players = new List(512); private readonly List _nextPlayers = new List(512); private readonly Dictionary _byId = new Dictionary(512); private int _cursor; private int _discoveryCursor; private float _nextDiscovery; private float _nextWarning; private bool _disposed; public string Status { get; private set; } = "Pooled audio monitor waiting for gameplay"; internal int PlayerCount => _players.Count; public WorldAudioMonitor(Action registerPlayingSource, Action warning) { _registerPlayingSource = registerPlayingSource; _warning = warning; } public void Tick(float now) { if (_disposed || !float.IsFinite(now)) { return; } if (now >= _nextDiscovery) { _nextDiscovery = now + 0.5f; Discover(now); } int num = Math.Min(64, _players.Count); for (int i = 0; i < num; i++) { if (_cursor >= _players.Count) { _cursor = 0; } PlaybackState playbackState = _players[_cursor++]; try { Observe(playbackState); } catch (Exception ex) { playbackState.WasPlaying = false; Warn(now, "A pooled audio player became unavailable: " + ex.GetType().Name); } } } private void Observe(PlaybackState state) { AudioPlayer player = state.Player; if ((Object)(object)player == (Object)null || !((Behaviour)player).isActiveAndEnabled || ((SpawnEvents)player).IsDespawned) { state.WasPlaying = false; return; } AudioSource source = player.source; if ((Object)(object)source == (Object)null || !((Behaviour)source).isActiveAndEnabled || !source.isPlaying || source.mute || source.volume <= 0f) { state.WasPlaying = false; return; } ulong iD = ((SpawnEvents)player).ID; AudioClip clip = source.clip; int num = ((!source.loop) ? source.timeSamples : 0); bool flag = !source.loop && source.pitch > 0f && num >= 0 && (long)num + 32L < state.Samples; bool num2 = !state.WasPlaying || (Object)(object)state.Source != (Object)(object)source || (Object)(object)state.Clip != (Object)(object)clip || state.Generation != iD || flag; state.WasPlaying = true; state.Source = source; state.Clip = clip; state.Generation = iD; state.Samples = num; if (num2) { _registerPlayingSource(source); } } private void Discover(float now) { try { Il2CppArrayBase val = Object.FindObjectsOfType(true); _nextPlayers.Clear(); int num = Math.Min(val.Length, 512); if (_discoveryCursor >= val.Length) { _discoveryCursor = 0; } for (int i = 0; i < num; i++) { int num2 = (_discoveryCursor + i) % val.Length; AudioPlayer val2 = val[num2]; if (!((Object)(object)val2 == (Object)null)) { int instanceID = ((Object)val2).GetInstanceID(); if (!_byId.TryGetValue(instanceID, out PlaybackState value) || (Object)(object)value.Player != (Object)(object)val2) { value = new PlaybackState(val2); } _nextPlayers.Add(value); } } _discoveryCursor = ((val.Length > 512) ? ((_discoveryCursor + 512) % val.Length) : 0); _players.Clear(); _byId.Clear(); foreach (PlaybackState nextPlayer in _nextPlayers) { if (!((Object)(object)nextPlayer.Player == (Object)null)) { _players.Add(nextPlayer); _byId[((Object)nextPlayer.Player).GetInstanceID()] = nextPlayer; } } _nextPlayers.Clear(); if (_cursor >= _players.Count) { _cursor = 0; } Status = "Pooled audio monitor active (" + _players.Count + "; no native hooks)"; } catch (Exception ex) { _nextPlayers.Clear(); Status = "Pooled audio discovery unavailable; regular sampling active"; Warn(now, "Pooled audio discovery was unavailable: " + ex.GetType().Name); } } private void Warn(float now, string message) { if (now < _nextWarning) { return; } _nextWarning = now + 10f; try { _warning(message); } catch { } } public void Reset() { _players.Clear(); _nextPlayers.Clear(); _byId.Clear(); _cursor = 0; _discoveryCursor = 0; _nextDiscovery = 0f; _nextWarning = 0f; if (!_disposed) { Status = "Pooled audio monitor waiting for gameplay"; } } public void Dispose() { if (!_disposed) { _disposed = true; Reset(); Status = "Pooled audio monitor disposed"; } } } internal sealed class WorldSoundInput : IDisposable { private sealed class SourceState { public readonly AudioSource Source; public bool WasPlaying; public bool Armed = true; public float LastLevel; public float RawLevel; public float Envelope; public float LastSample; public float LastFire = float.NegativeInfinity; public float DistanceSquared; public float LastVisit = float.NegativeInfinity; public float LastNotification = float.NegativeInfinity; public float RetryUntil; public float NextRetry; public bool HasPlayback; public Vector3 PlaybackOrigin; public float PlaybackTime; public AudioClip? PlaybackClip; public SoundEmitterSurface? PlaybackSurface; public bool PlaybackResolutionAttempted; public SourceState(AudioSource source) { Source = source; } public void Silence() { WasPlaying = false; Armed = true; LastLevel = 0f; Envelope = 0f; } } private const int MaximumSources = 512; private const int SampleCount = 256; private const float SampleInterval = 0.05f; private const float DiscoveryInterval = 1.5f; private const int MaximumStartedSources = 64; private const int StartedReadsPerFrame = 8; private const float StartedRetryInterval = 0.015f; private const float StartedRetryLifetime = 0.3f; private readonly Settings _settings; private readonly Action _warning; private readonly NpcSoundSources _npcSources; private readonly Func? _resolveSurface; private readonly Il2CppStructArray _samples = new Il2CppStructArray(256L); private readonly List _sources = new List(512); private readonly Dictionary _byId = new Dictionary(512); private readonly List _nextSources = new List(512); private readonly List _startedSources = new List(64); private int _cursor; private int _startedCursor; private float _nextDiscovery; private float _nextSample; private float _nextWarning; private bool _disposed; private Vector3 _lastHead; private bool _hasHead; public int SourceCount => _sources.Count; internal int PendingStartCount => _startedSources.Count; public float PeakLevel { get; private set; } public string Status { get; private set; } = "Waiting for nearby sounds"; public WorldSoundInput(Settings settings, Action warning, Func? resolveSurface = null) { _settings = settings; _warning = warning; _npcSources = new NpcSoundSources(warning); _resolveSurface = resolveSurface; } internal void RegisterPlayingSource(AudioSource source, SoundEmitterSurface? surfaceEmission = null) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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_0078: 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: 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_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) if (_disposed || !_settings.WorldSoundEnabled) { return; } float unscaledTime = Time.unscaledTime; try { if (!float.IsFinite(unscaledTime) || !Eligible(source)) { return; } Vector3 val = (Vector3)(((??)surfaceEmission?.Origin) ?? ((Component)source).transform.position); float num; Vector3 val2; if (!_hasHead) { num = 0f; } else { val2 = val - _lastHead; num = ((Vector3)(ref val2)).sqrMagnitude; } float num2 = num; float num3 = Mathf.Clamp(_settings.WorldRange, 1f, 200f); bool flag = surfaceEmission == null && _resolveSurface != null; if (!float.IsFinite(num2) || (num2 > num3 * num3 && !flag)) { return; } int instanceID = ((Object)source).GetInstanceID(); if (!_byId.TryGetValue(instanceID, out SourceState value) || (Object)(object)value.Source != (Object)(object)source) { if (_sources.Count == 512) { int index = 0; for (int i = 1; i < _sources.Count; i++) { if (_sources[i].DistanceSquared > _sources[index].DistanceSquared) { index = i; } } SourceState sourceState = _sources[index]; if ((Object)(object)sourceState.Source != (Object)null) { _byId.Remove(((Object)sourceState.Source).GetInstanceID()); } _startedSources.Remove(sourceState); _sources.RemoveAt(index); } value = new SourceState(source); _sources.Add(value); _byId[instanceID] = value; } int num4; if (value.LastNotification == unscaledTime && (Object)(object)value.PlaybackClip == (Object)(object)source.clip) { val2 = value.PlaybackOrigin - val; num4 = ((((Vector3)(ref val2)).sqrMagnitude < 1E-06f) ? 1 : 0); } else { num4 = 0; } value.LastNotification = unscaledTime; value.DistanceSquared = num2; if (num4 == 0) { value.Silence(); value.LastFire = float.NegativeInfinity; } value.HasPlayback = true; value.PlaybackOrigin = val; value.PlaybackTime = unscaledTime; value.PlaybackClip = source.clip; value.PlaybackSurface = surfaceEmission; value.PlaybackResolutionAttempted = false; value.RetryUntil = unscaledTime + 0.3f; value.NextRetry = unscaledTime + 0.015f; if (!_startedSources.Contains(value)) { if (_startedSources.Count == 64) { _startedSources.RemoveAt(0); } _startedSources.Add(value); } } catch (Exception ex) { WarnOnce(unscaledTime, "A started audio source became unavailable: " + ex.GetType().Name); } } public void Tick(float now, Vector3 head, Action emit, Action? observeSound = null) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) if (_disposed) { return; } if (!_settings.WorldSoundEnabled) { if (_sources.Count != 0) { Reset(); } Status = "World sound disabled"; return; } bool flag = now >= _nextSample; if (!flag && _startedSources.Count == 0) { return; } _lastHead = head; _hasHead = true; if (flag) { _nextSample = now + 0.05f; PeakLevel *= 0.8f; if (now >= _nextDiscovery) { _nextDiscovery = now + 1.5f; Discover(now, head); } } int reads = 0; int num = 0; int num2 = Mathf.Clamp(_settings.SourcesPerTick, 1, 64); EchoEvent strongest = default(EchoEvent); SourceState strongestState = null; int num3 = 0; int count = _startedSources.Count; while (_startedSources.Count > 0 && num3++ < count && reads < Math.Min(num2, 8)) { if (_startedCursor >= _startedSources.Count) { _startedCursor = 0; } int startedCursor = _startedCursor; SourceState sourceState = _startedSources[startedCursor]; if (now > sourceState.RetryUntil || (Object)(object)sourceState.Source == (Object)null) { ClearPlayback(sourceState); _startedSources.RemoveAt(startedCursor); continue; } if (now < sourceState.NextRetry) { _startedCursor++; continue; } sourceState.NextRetry = now + 0.015f; if (SampleSource(sourceState, now, head, emit, observeSound, ref reads, ref strongest, ref strongestState)) { _startedSources.RemoveAt(startedCursor); } else { _startedCursor++; } } while (flag && num < _sources.Count && reads < num2) { if (_cursor >= _sources.Count) { _cursor = 0; } SourceState sourceState2 = _sources[_cursor++]; num++; if (sourceState2.LastVisit != now && (!sourceState2.HasPlayback || now >= sourceState2.NextRetry)) { SampleSource(sourceState2, now, head, emit, observeSound, ref reads, ref strongest, ref strongestState); } } if (strongestState != null) { try { AudioSource source = strongestState.Source; if ((Object)(object)source != (Object)null && ((Behaviour)source).isActiveAndEnabled) { EmitCaptured(strongestState, strongest, emit); } } catch (Exception ex) { strongestState.Silence(); WarnOnce(now, "A world audio source became unavailable: " + ex.GetType().Name); } } Status = ((_sources.Count == 0) ? "No nearby 3D audio sources" : "Listening to nearby 3D sounds"); } private bool SampleSource(SourceState state, float now, Vector3 head, Action emit, Action? observeSound, ref int reads, ref EchoEvent strongest, ref SourceState? strongestState) { //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_02c3: Unknown result type (might be due to invalid IL or missing references) //IL_0205: 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_020d: 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_0210: 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_0217: 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_0219: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_022c: 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) state.LastVisit = now; try { AudioSource source = state.Source; if (state.HasPlayback && ((Object)(object)source == (Object)null || (Object)(object)source.clip != (Object)(object)state.PlaybackClip || now > state.RetryUntil)) { ClearPlayback(state); } if ((Object)(object)source == (Object)null || !source.isPlaying || source.isVirtual || (AudioListener.pause && !source.ignoreListenerPause) || !Eligible(source)) { state.Silence(); return false; } Vector3 val = (state.HasPlayback ? state.PlaybackOrigin : ((Component)source).transform.position); float num = Vector3.Distance(val, head); bool flag = state.HasPlayback && state.PlaybackSurface == null && !state.PlaybackResolutionAttempted && _resolveSurface != null; if (!float.IsFinite(num) || (num > Mathf.Clamp(_settings.WorldRange, 1f, 200f) && !flag)) { state.Silence(); return false; } reads++; source.GetOutputData(_samples, 0); double num2 = 0.0; for (int i = 0; i < 256; i++) { float num3 = ((Il2CppArrayBase)(object)_samples)[i]; num2 += (double)(num3 * num3); } float num4 = (source.ignoreListenerVolume ? 1f : AudioListener.volume); float num5 = (float)Math.Sqrt(num2 / 256.0) * source.volume * Mathf.Clamp01(num4); if (!float.IsFinite(num5)) { num5 = 0f; } state.RawLevel = num5; float num6 = Mathf.Clamp(_settings.SoundThreshold, 0.0001f, 1f); if (flag && num5 >= num6) { state.PlaybackResolutionAttempted = true; state.PlaybackSurface = _resolveSurface(now, source); Vector3? val2 = state.PlaybackSurface?.Origin; if (val2.HasValue) { Vector3 valueOrDefault = val2.GetValueOrDefault(); val = (state.PlaybackOrigin = valueOrDefault); Vector3 val3 = val - head; state.DistanceSquared = ((Vector3)(ref val3)).sqrMagnitude; num = Vector3.Distance(val, head); } } if (num > Mathf.Clamp(_settings.WorldRange, 1f, 200f)) { state.Silence(); return false; } float num7 = num5 * EstimateRolloff(source, num); if (!float.IsFinite(num7)) { num7 = 0f; } num7 = Mathf.Clamp01(num7); PeakLevel = Mathf.Max(PeakLevel, num7); bool num8 = num7 >= num6; float strength = Mathf.Lerp(0.3f, 1f, Mathf.Clamp01(num7 / (num6 * 5f))); EchoEvent echoEvent = new EchoEvent(val, strength, EchoKind.World, state.HasPlayback ? state.PlaybackTime : now, -1, source); if (num8) { observeSound?.Invoke(echoEvent.WithTime(now)); } float num9 = Mathf.Clamp(_settings.SoundCooldown, 0.1f, 10f); bool flag2 = !state.WasPlaying; if (num7 < num6 * 0.55f) { state.Armed = true; } bool flag3 = num7 > state.LastLevel * 1.9f && num7 > state.Envelope * 1.6f && num7 >= num6 * 1.2f; bool num10 = num8 && (state.Armed || flag2 || flag3) && now - state.LastFire >= num9; float num11 = Mathf.Clamp(now - state.LastSample, 0.05f, 2f); state.Envelope = Mathf.Lerp(state.Envelope, num7, 1f - Mathf.Exp((0f - num11) / 0.6f)); state.LastLevel = num7; state.LastSample = now; state.WasPlaying = true; if (num10) { state.Armed = false; state.LastFire = now; if (state.HasPlayback) { EmitCaptured(state, echoEvent, emit); } else if (strongestState == null || echoEvent.Strength > strongest.Strength) { strongest = echoEvent; strongestState = state; } } if (num8) { ClearPlayback(state); } return num8; } catch (Exception ex) { state.Silence(); WarnOnce(now, "A world audio source became unavailable: " + ex.GetType().Name); return false; } } private void EmitCaptured(SourceState state, EchoEvent echo, Action emit) { //IL_0092: 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_0097: 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_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) AudioSource source = state.Source; SoundEmitterSurface soundEmitterSurface = (state.HasPlayback ? state.PlaybackSurface : null); if (soundEmitterSurface == null && (!state.HasPlayback || !state.PlaybackResolutionAttempted)) { soundEmitterSurface = _resolveSurface?.Invoke(echo.Time, source); } NpcSoundEmission npcSoundEmission = soundEmitterSurface as NpcSoundEmission; if (soundEmitterSurface == null) { npcSoundEmission = _npcSources.Capture(echo.Time, source); soundEmitterSurface = npcSoundEmission; } Vector3 val = (Vector3)(((??)soundEmitterSurface?.Origin) ?? echo.Origin); float strength = echo.Strength; if (_hasHead && soundEmitterSurface != null && soundEmitterSurface.Origin.HasValue) { float num = Vector3.Distance(val, _lastHead); if (num > _settings.WorldRange) { return; } float num2 = Mathf.Clamp01(state.RawLevel * EstimateRolloff(source, num)); float num3 = Mathf.Clamp(_settings.SoundThreshold, 0.0001f, 1f); if (num2 < num3) { return; } strength = Mathf.Lerp(0.3f, 1f, Mathf.Clamp01(num2 / (num3 * 5f))); } emit(new EchoEvent(val, strength, EchoKind.World, echo.Time, -1, source, npcSoundEmission, soundEmitterSurface)); } private static void ClearPlayback(SourceState state) { state.HasPlayback = false; state.PlaybackSurface = null; state.PlaybackClip = null; state.PlaybackResolutionAttempted = false; } private void Discover(float now, Vector3 head) { //IL_0099: 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_009e: 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_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: 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_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: 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) _nextSources.Clear(); try { Il2CppArrayBase val = Object.FindObjectsOfType(); float num = Mathf.Clamp(_settings.WorldRange, 1f, 200f) + 5f; float num2 = num * num; Vector3 val3; for (int i = 0; i < val.Length; i++) { AudioSource val2 = val[i]; try { if (!Eligible(val2)) { continue; } int instanceID = ((Object)val2).GetInstanceID(); if (!_byId.TryGetValue(instanceID, out SourceState value) || (Object)(object)value.Source != (Object)(object)val2) { value = new SourceState(val2); } val3 = (value.HasPlayback ? value.PlaybackOrigin : ((Component)val2).transform.position) - head; float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude; bool flag = value.HasPlayback && value.PlaybackSurface == null && !value.PlaybackResolutionAttempted && _resolveSurface != null; if (!float.IsFinite(sqrMagnitude) || (sqrMagnitude > num2 && !flag)) { continue; } value.DistanceSquared = sqrMagnitude; int num3 = FindInsertion(sqrMagnitude); if (num3 < 512) { if (_nextSources.Count == 512) { _nextSources.RemoveAt(511); } _nextSources.Insert(num3, value); } } catch (Exception ex) { WarnOnce(now, "A pooled audio source was skipped: " + ex.GetType().Name); } } foreach (SourceState startedSource in _startedSources) { if ((Object)(object)startedSource.Source == (Object)null || now > startedSource.RetryUntil || _nextSources.Contains(startedSource)) { continue; } Vector3 val4 = (startedSource.HasPlayback ? startedSource.PlaybackOrigin : ((Component)startedSource.Source).transform.position); val3 = val4 - head; startedSource.DistanceSquared = ((Vector3)(ref val3)).sqrMagnitude; bool flag2 = startedSource.HasPlayback && startedSource.PlaybackSurface == null && !startedSource.PlaybackResolutionAttempted && _resolveSurface != null; if (!float.IsFinite(startedSource.DistanceSquared) || (startedSource.DistanceSquared > num2 && !flag2)) { continue; } int num4 = FindInsertion(startedSource.DistanceSquared); if (num4 < 512) { if (_nextSources.Count == 512) { _nextSources.RemoveAt(511); } _nextSources.Insert(num4, startedSource); } } } catch (Exception ex2) { WarnOnce(now, "Could not refresh world audio sources: " + ex2.GetType().Name); return; } _sources.Clear(); _sources.AddRange(_nextSources); _byId.Clear(); foreach (SourceState source in _sources) { if ((Object)(object)source.Source != (Object)null) { _byId[((Object)source.Source).GetInstanceID()] = source; } } if (_cursor >= _sources.Count) { _cursor = 0; } } private int FindInsertion(float distanceSquared) { int num = 0; int num2 = _nextSources.Count; while (num < num2) { int num3 = (num + num2) / 2; if (_nextSources[num3].DistanceSquared <= distanceSquared) { num = num3 + 1; } else { num2 = num3; } } return num; } private bool Eligible(AudioSource source) { if ((Object)(object)source == (Object)null || !((Behaviour)source).isActiveAndEnabled || source.mute || source.volume <= 0f || source.spatialBlend < 0.5f || (source.loop && !_settings.IncludeLoopingAudio)) { return false; } Transform val = ((Component)source).transform; int num = 0; while (num < 4 && (Object)(object)val != (Object)null) { string name = ((Object)val).name; if (name.StartsWith("Voice Source ", StringComparison.OrdinalIgnoreCase) || name.StartsWith("Echolocation", StringComparison.OrdinalIgnoreCase)) { return false; } num++; val = val.parent; } return true; } private static float EstimateRolloff(AudioSource source, float distance) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Invalid comparison between Unknown and I4 float num = Mathf.Max(source.minDistance, 0.01f); float num2 = Mathf.Max(source.maxDistance, num + 0.01f); if (distance <= num) { return 1f; } if ((int)source.rolloffMode == 1) { return Mathf.Clamp01(1f - (distance - num) / (num2 - num)); } return Mathf.Clamp01(num / Mathf.Min(distance, num2)); } private void WarnOnce(float now, string message) { if (!(now < _nextWarning)) { _nextWarning = now + 10f; _warning(message); } } public void Reset() { _npcSources.Reset(); _sources.Clear(); _nextSources.Clear(); _byId.Clear(); _startedSources.Clear(); _cursor = 0; _startedCursor = 0; _nextDiscovery = 0f; _nextSample = 0f; PeakLevel = 0f; _hasHead = false; Status = "Waiting for nearby sounds"; } public void Dispose() { Reset(); _disposed = true; } } }