Decompiled source of VoicePower v1.0.0

Mods/VoicePower.dll

Decompiled 7 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BoneLib;
using BoneLib.BoneMenu;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSLZ.Marrow;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;
using VoicePowerMod;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(VoicePowerController), "VoicePower", "1.0.0", "VoidIndustries", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: MelonPlatform(/*Could not decode attribute arguments.*/)]
[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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace VoicePowerMod
{
	internal static class Il2CppHelper
	{
		private static MethodInfo _addComponentMethod;

		internal static T AddComponent<T>(GameObject go) where T : Component
		{
			try
			{
				return go.AddComponent<T>();
			}
			catch (TypeInitializationException)
			{
				MelonLogger.Warning("[VoicePower] Generic AddComponent failed for " + typeof(T).Name + ", using reflection fallback");
				return AddComponentViaReflection<T>(go);
			}
			catch (Exception ex2)
			{
				MelonLogger.Error("[VoicePower] AddComponent failed for " + typeof(T).Name + ": " + ex2.Message);
				return default(T);
			}
		}

		private static T AddComponentViaReflection<T>(GameObject go) where T : Component
		{
			if (_addComponentMethod == null)
			{
				_addComponentMethod = typeof(GameObject).GetMethod("AddComponent", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(Type) }, null);
				if (_addComponentMethod == null)
				{
					MelonLogger.Error("[VoicePower] Could not find AddComponent(Il2CppSystem.Type) method");
					return default(T);
				}
			}
			Type val = Il2CppType.Of<T>();
			object obj = _addComponentMethod.Invoke(go, new object[1] { val });
			return (T)((obj is T) ? obj : null);
		}
	}
	[RegisterTypeInIl2Cpp]
	public class MicrophoneInput : MonoBehaviour
	{
		private const int SAMPLE_SIZE = 2048;

		private const float WHISPER_THRESHOLD = 0.015f;

		private const float SCREAM_THRESHOLD = 0.18f;

		private const float SOUND_NOISE_FLOOR = 0.002f;

		private const float SOUND_FULL_SCALE = 0.08f;

		private float[] _sampleData;

		private float[] _readBuffer;

		private bool _isMicrophoneActive;

		private bool _wasScreaming;

		private float _smoothedVolume;

		private const float SMOOTHING = 0.2f;

		private int _analyzeLogCounter;

		public float CurrentVolume { get; private set; }

		public float DominantFrequency { get; private set; }

		public bool IsWhispering { get; private set; }

		public bool IsScreaming { get; private set; }

		public bool JustScreamed { get; private set; }

		public float LowFrequencyEnergy { get; private set; }

		public float HighFrequencyEnergy { get; private set; }

		public bool IsMicrophoneActive
		{
			get
			{
				if (_isMicrophoneActive)
				{
					return WindowsMicCapture.IsRecording;
				}
				return false;
			}
		}

		public float RawVolume { get; private set; }

		public bool HasSound { get; private set; }

		public float SoundIntensity { get; private set; }

		public MicrophoneInput(IntPtr pointer)
			: base(pointer)
		{
		}

		private void Start()
		{
			_sampleData = new float[2048];
			_readBuffer = new float[2048];
			int deviceIndex = -1;
			try
			{
				MelonPreferences_Category category = MelonPreferences.GetCategory("VoicePower");
				if (category != null)
				{
					MelonPreferences_Entry<int> entry = category.GetEntry<int>("MicDevice");
					if (entry != null)
					{
						deviceIndex = entry.Value;
						MelonLogger.Msg("[VoicePower] MicrophoneInput: loaded MicDevice=" + deviceIndex + " from settings");
					}
					else
					{
						MelonLogger.Msg("[VoicePower] MicrophoneInput: MicDevice entry not found, using default");
					}
				}
				else
				{
					MelonLogger.Msg("[VoicePower] MicrophoneInput: VoicePower category not found");
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[VoicePower] MicrophoneInput: failed to read settings: " + ex.Message);
			}
			_isMicrophoneActive = WindowsMicCapture.Start(44100, 1, deviceIndex);
			MelonLogger.Msg("[VoicePower] MicrophoneInput: _isMicrophoneActive=" + _isMicrophoneActive + " recording=" + WindowsMicCapture.IsRecording + " rate=" + WindowsMicCapture.SampleRate + " callbacks=" + WindowsMicCapture.CallbackCount);
			if (!_isMicrophoneActive)
			{
				MelonLogger.Error("[VoicePower] MicrophoneInput: FAILED to start Windows mic capture!");
				ResetAudioState();
			}
		}

		private void Update()
		{
			if (!_isMicrophoneActive || !WindowsMicCapture.IsRecording)
			{
				ResetAudioState();
			}
			else
			{
				AnalyzeAudio();
			}
		}

		private void AnalyzeAudio()
		{
			int num = WindowsMicCapture.AvailableSamples();
			_analyzeLogCounter++;
			if (_analyzeLogCounter % 120 == 0)
			{
				MelonLogger.Msg("[VoicePower] Analyze: active=" + _isMicrophoneActive + " avail=" + num + " need=" + 1024);
			}
			if (num < 1024)
			{
				return;
			}
			int num2 = WindowsMicCapture.ReadSamples(_readBuffer, 2048);
			if (num2 >= 1024)
			{
				Array.Copy(_readBuffer, _sampleData, num2);
				float num3 = (RawVolume = CalculateRMS(_sampleData, num2));
				HasSound = num3 > 0.002f;
				SoundIntensity = (HasSound ? Mathf.Clamp(Mathf.InverseLerp(0.002f, 0.08f, num3), 0.15f, 1f) : 0f);
				_smoothedVolume = Mathf.Lerp(_smoothedVolume, num3, 0.2f);
				CurrentVolume = _smoothedVolume;
				int sampleRate = WindowsMicCapture.SampleRate;
				DominantFrequency = EstimateFrequency(_sampleData, num2, sampleRate);
				LowFrequencyEnergy = EstimateBandEnergy(_sampleData, num2, 0f, 300f, sampleRate);
				HighFrequencyEnergy = EstimateBandEnergy(_sampleData, num2, 2000f, 8000f, sampleRate);
				IsWhispering = CurrentVolume > 0.015f;
				IsScreaming = CurrentVolume > 0.18f;
				JustScreamed = IsScreaming && !_wasScreaming;
				_wasScreaming = IsScreaming;
				_analyzeLogCounter++;
				if (_analyzeLogCounter % 120 == 0)
				{
					MelonLogger.Msg("[VoicePower] Analyze: active=" + IsMicrophoneActive + " vol=" + CurrentVolume.ToString("F4") + " raw=" + RawVolume.ToString("F4") + " rms=" + num3.ToString("F4") + " whisper=" + IsWhispering + " scream=" + IsScreaming + " avail=" + num + " read=" + num2 + " callbacks=" + WindowsMicCapture.CallbackCount);
				}
			}
		}

		private static float CalculateRMS(float[] samples, int count)
		{
			float num = 0f;
			for (int i = 0; i < count; i++)
			{
				num += samples[i] * samples[i];
			}
			return Mathf.Sqrt(num / (float)count);
		}

		private static float EstimateFrequency(float[] samples, int count, int sampleRate)
		{
			if (count < 2 || sampleRate <= 0)
			{
				return 0f;
			}
			int num = 0;
			for (int i = 1; i < count; i++)
			{
				if ((samples[i] >= 0f && samples[i - 1] < 0f) || (samples[i] < 0f && samples[i - 1] >= 0f))
				{
					num++;
				}
			}
			return (float)num * 0.5f * (float)sampleRate / (float)count;
		}

		private static float EstimateBandEnergy(float[] samples, int count, float lowHz, float highHz, int sampleRate)
		{
			if (count < 10 || sampleRate <= 0)
			{
				return 0f;
			}
			int num = ((lowHz <= 0f) ? 1 : Mathf.Max(1, (int)((float)sampleRate / lowHz)));
			int num2 = ((highHz <= 0f) ? 1 : Mathf.Max(1, (int)((float)sampleRate / highHz)));
			float num3 = 0f;
			float num4 = 0f;
			int num5 = 0;
			int num6 = 0;
			for (int i = num; i < count; i++)
			{
				num3 += samples[i] * samples[i - num];
				num5++;
			}
			for (int j = num2; j < count; j++)
			{
				num4 += samples[j] * samples[j - num2];
				num6++;
			}
			float result = ((num5 > 0) ? Mathf.Abs(num3 / (float)num5) : 0f);
			float result2 = ((num6 > 0) ? Mathf.Abs(num4 / (float)num6) : 0f);
			if (!(lowHz <= 300f))
			{
				return result2;
			}
			return result;
		}

		private void ResetAudioState()
		{
			RawVolume = 0f;
			HasSound = false;
			SoundIntensity = 0f;
			_smoothedVolume = 0f;
			CurrentVolume = 0f;
			DominantFrequency = 0f;
			LowFrequencyEnergy = 0f;
			HighFrequencyEnergy = 0f;
			IsWhispering = false;
			IsScreaming = false;
			JustScreamed = false;
			_wasScreaming = false;
		}

		private void OnDestroy()
		{
			if (_isMicrophoneActive)
			{
				WindowsMicCapture.Stop();
				_isMicrophoneActive = false;
			}
		}
	}
	[RegisterTypeInIl2Cpp]
	public class ShockwaveEffect : MonoBehaviour
	{
		private sealed class WaveRing
		{
			public GameObject Object;

			public LineRenderer Renderer;

			public float Age;

			public float Lifetime;

			public float Radius;

			public float MaxRadius;

			public Color Color;

			public Vector3 Center;

			public Vector3 Forward;
		}

		private MicrophoneInput _micInput;

		private VoiceForceApplier _forceApplier;

		private ParticleSystem _particleSystem;

		private GameObject _particleObj;

		private Material _ringMaterial;

		private readonly List<WaveRing> _activeRings = new List<WaveRing>();

		private float _lastShockwaveTime = -999f;

		private float _nextVoiceWaveTime;

		private float _lastWaveLogTime = -999f;

		private const float SCREAM_COOLDOWN = 2f;

		private const float SPEECH_WAVE_INTERVAL = 0.1f;

		private const float SHOCKWAVE_RADIUS = 10f;

		private const float SHOCKWAVE_FORCE = 120f;

		private const float SOUND_WAVE_MIN_RADIUS = 2.5f;

		private const float SOUND_WAVE_MAX_RADIUS = 14f;

		private const float SOUND_WAVE_MIN_FORCE = 35f;

		private const float SOUND_WAVE_MAX_FORCE = 260f;

		private const int RING_SEGMENTS = 32;

		private const int MAX_ACTIVE_RINGS = 12;

		public ShockwaveEffect(IntPtr pointer)
			: base(pointer)
		{
		}

		private void Start()
		{
			_micInput = ((Component)this).GetComponent<MicrophoneInput>();
			_forceApplier = ((Component)this).GetComponent<VoiceForceApplier>();
			CreateShockwaveParticleSystem();
			_ringMaterial = CreateShockwaveMaterial();
		}

		private void Update()
		{
			if (!((Object)(object)_micInput == (Object)null))
			{
				float unscaledTime = Time.unscaledTime;
				if (_micInput.IsMicrophoneActive && _micInput.HasSound && unscaledTime >= _nextVoiceWaveTime)
				{
					EmitSpeechWave();
					_nextVoiceWaveTime = unscaledTime + 0.1f;
				}
				if (_micInput.JustScreamed && unscaledTime - _lastShockwaveTime >= 2f)
				{
					TriggerShockwave();
					_lastShockwaveTime = unscaledTime;
				}
				UpdateRings(Time.unscaledDeltaTime);
			}
		}

		private void EmitSpeechWave()
		{
			//IL_0062: 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_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_007c: 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_0098: 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_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			Transform head = Player.Head;
			if (!((Object)(object)head == (Object)null))
			{
				float num = Mathf.Clamp01(_micInput.SoundIntensity);
				float num2 = Mathf.Lerp(2.5f, 14f, num);
				float force = Mathf.Lerp(35f, 260f, num) * VoicePowerController.VoicePowerMultiplier;
				float upwardForce = Mathf.Lerp(6f, 35f, num) * VoicePowerController.VoicePowerMultiplier;
				Vector3 center = head.position + head.forward * 0.18f;
				int affected = (((Object)(object)_forceApplier != (Object)null) ? _forceApplier.ApplyVoiceWave(center, head.forward, num2, force, upwardForce) : 0);
				Color color = ((num > 0.75f) ? new Color(1f, 0.35f, 0.1f, 0.8f) : new Color(0.25f, 0.75f, 1f, 0.65f));
				CreateRing(center, head.forward, num2, 0.45f, color);
				LogWave((num > 0.75f) ? "LOUD WAVE" : "SOUND WAVE", num, num2, force, affected);
			}
		}

		private void TriggerShockwave()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: 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_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: 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_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			Transform head = Player.Head;
			if (!((Object)(object)head == (Object)null))
			{
				Vector3 val = head.position + head.forward * 0.2f;
				float num = Mathf.Clamp01(_micInput.CurrentVolume * 3f);
				float num2 = Mathf.Lerp(7.5f, 13.5f, num);
				float num3 = Mathf.Lerp(120f, 216f, num) * VoicePowerController.VoicePowerMultiplier;
				if ((Object)(object)_particleObj != (Object)null && (Object)(object)_particleSystem != (Object)null)
				{
					_particleObj.transform.position = val;
					_particleObj.transform.rotation = Quaternion.LookRotation(head.forward);
					_particleObj.transform.localScale = Vector3.one * (num2 / 8f);
					_particleSystem.Clear();
					_particleSystem.Play();
				}
				int affected = (((Object)(object)_forceApplier != (Object)null) ? _forceApplier.ApplyVoiceWave(val, head.forward, num2, num3, num3 * 0.2f) : 0);
				CreateRing(val, head.forward, num2, 0.9f, new Color(1f, 0.25f, 0.15f, 0.9f));
				CreateRing(val, head.forward, num2 * 0.65f, 0.65f, new Color(1f, 0.85f, 0.25f, 0.7f));
				LogWave("SCREAM WAVE", num, num2, num3, affected);
			}
		}

		private void CreateRing(Vector3 center, Vector3 forward, float maxRadius, float lifetime, Color color)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: 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_00ee: 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_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: 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)
			if (!((Object)(object)_ringMaterial == (Object)null) && _activeRings.Count < 12)
			{
				GameObject val = new GameObject("VoicePower_WaveRing");
				LineRenderer val2 = Il2CppHelper.AddComponent<LineRenderer>(val);
				if ((Object)(object)val2 == (Object)null)
				{
					Object.Destroy((Object)(object)val);
					return;
				}
				val2.useWorldSpace = true;
				val2.loop = true;
				val2.positionCount = 32;
				val2.startWidth = 0.025f;
				val2.endWidth = 0.003f;
				((Renderer)val2).material = _ringMaterial;
				val2.startColor = color;
				val2.endColor = new Color(color.r, color.g, color.b, 0f);
				((Renderer)val2).shadowCastingMode = (ShadowCastingMode)0;
				((Renderer)val2).receiveShadows = false;
				WaveRing waveRing = new WaveRing
				{
					Object = val,
					Renderer = val2,
					Age = 0f,
					Lifetime = lifetime,
					Radius = 0.05f,
					MaxRadius = maxRadius,
					Color = color,
					Center = center,
					Forward = ((Vector3)(ref forward)).normalized
				};
				_activeRings.Add(waveRing);
				UpdateRing(waveRing);
			}
		}

		private void UpdateRings(float deltaTime)
		{
			for (int num = _activeRings.Count - 1; num >= 0; num--)
			{
				WaveRing waveRing = _activeRings[num];
				waveRing.Age += deltaTime;
				if (waveRing.Age >= waveRing.Lifetime || (Object)(object)waveRing.Object == (Object)null || (Object)(object)waveRing.Renderer == (Object)null)
				{
					if ((Object)(object)waveRing.Object != (Object)null)
					{
						Object.Destroy((Object)(object)waveRing.Object);
					}
					_activeRings.RemoveAt(num);
				}
				else
				{
					waveRing.Radius = Mathf.Lerp(0.05f, waveRing.MaxRadius, waveRing.Age / waveRing.Lifetime);
					UpdateRing(waveRing);
				}
			}
		}

		private void UpdateRing(WaveRing ring)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00af: 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_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: 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_00fd: 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_0116: 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_012a: 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_013d: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = ((((Vector3)(ref ring.Forward)).sqrMagnitude > 0.001f) ? ring.Forward : Vector3.forward);
			Vector3 val2 = Vector3.Cross(Vector3.up, val);
			if (((Vector3)(ref val2)).sqrMagnitude < 0.001f)
			{
				val2 = Vector3.Cross(Vector3.right, val);
			}
			((Vector3)(ref val2)).Normalize();
			Vector3 val3 = Vector3.Cross(val, val2);
			Vector3 normalized = ((Vector3)(ref val3)).normalized;
			for (int i = 0; i < 32; i++)
			{
				float num = (float)i / 32f * (float)Math.PI * 2f;
				Vector3 val4 = (val2 * Mathf.Cos(num) + normalized * Mathf.Sin(num)) * ring.Radius;
				ring.Renderer.SetPosition(i, ring.Center + val * (ring.Radius * 0.35f) + val4);
			}
			float num2 = 1f - Mathf.Clamp01(ring.Age / ring.Lifetime);
			Color color = ring.Color;
			color.a *= num2;
			ring.Renderer.startColor = color;
			ring.Renderer.endColor = new Color(color.r, color.g, color.b, 0f);
		}

		private void LogWave(string type, float volume, float radius, float force, int affected)
		{
			float unscaledTime = Time.unscaledTime;
			if (!(type == "VOICE WAVE") || !(unscaledTime - _lastWaveLogTime < 1f))
			{
				_lastWaveLogTime = unscaledTime;
				MelonLogger.Msg("[VoicePower] " + type + " volume=" + volume.ToString("F2") + " radius=" + radius.ToString("F1") + " force=" + force.ToString("F1") + " affected=" + affected);
			}
		}

		private void CreateShockwaveParticleSystem()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_00b1: 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_011c: Expected O, but got Unknown
			_particleObj = new GameObject("VoicePower_Shockwave");
			_particleObj.transform.SetParent(((Component)this).transform, false);
			Object.DontDestroyOnLoad((Object)(object)_particleObj);
			_particleSystem = Il2CppHelper.AddComponent<ParticleSystem>(_particleObj);
			if (!((Object)(object)_particleSystem == (Object)null))
			{
				MainModule main = _particleSystem.main;
				main.loop = false;
				main.playOnAwake = false;
				main.startLifetime = MinMaxCurve.op_Implicit(0.8f);
				main.startSpeed = MinMaxCurve.op_Implicit(12f);
				main.startSize = MinMaxCurve.op_Implicit(0.4f);
				main.startColor = MinMaxGradient.op_Implicit(new Color(0.8f, 0.9f, 1f, 0.9f));
				main.maxParticles = 200;
				main.simulationSpace = (ParticleSystemSimulationSpace)1;
				main.gravityModifier = MinMaxCurve.op_Implicit(0f);
				EmissionModule emission = _particleSystem.emission;
				emission.rateOverTime = MinMaxCurve.op_Implicit(0f);
				emission.SetBursts(Il2CppReferenceArray<Burst>.op_Implicit((Burst[])(object)new Burst[1]
				{
					new Burst(0f, MinMaxCurve.op_Implicit(80f))
				}));
				ParticleSystemRenderer component = _particleObj.GetComponent<ParticleSystemRenderer>();
				if ((Object)(object)component != (Object)null)
				{
					component.renderMode = (ParticleSystemRenderMode)0;
					((Renderer)component).material = CreateShockwaveMaterial();
					((Renderer)component).shadowCastingMode = (ShadowCastingMode)0;
					((Renderer)component).receiveShadows = false;
				}
			}
		}

		private static Material CreateShockwaveMaterial()
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			Shader val = Shader.Find("Legacy Shaders/Particles/Additive");
			if ((Object)(object)val == (Object)null)
			{
				val = Shader.Find("Particles/Standard Unlit");
			}
			if ((Object)(object)val == (Object)null)
			{
				val = Shader.Find("Standard");
			}
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			Material val2 = new Material(val);
			val2.SetFloat("_Mode", 1f);
			val2.SetInt("_SrcBlend", 5);
			val2.SetInt("_DstBlend", 1);
			val2.SetInt("_ZWrite", 0);
			val2.DisableKeyword("_ALPHATEST_ON");
			val2.EnableKeyword("_ALPHABLEND_ON");
			val2.DisableKeyword("_ALPHAPREMULTIPLY_ON");
			val2.renderQueue = 3000;
			return val2;
		}

		private void OnDestroy()
		{
			for (int i = 0; i < _activeRings.Count; i++)
			{
				if ((Object)(object)_activeRings[i].Object != (Object)null)
				{
					Object.Destroy((Object)(object)_activeRings[i].Object);
				}
			}
			_activeRings.Clear();
			if ((Object)(object)_particleObj != (Object)null)
			{
				Object.Destroy((Object)(object)_particleObj);
			}
			if ((Object)(object)_ringMaterial != (Object)null)
			{
				Object.Destroy((Object)(object)_ringMaterial);
			}
		}
	}
	[RegisterTypeInIl2Cpp]
	public class VoiceForceApplier : MonoBehaviour
	{
		private MicrophoneInput _micInput;

		private readonly HashSet<Rigidbody> _playerRbs = new HashSet<Rigidbody>();

		private readonly HashSet<Rigidbody> _waveBodies = new HashSet<Rigidbody>();

		private readonly HashSet<Rigidbody> _loggedBodies = new HashSet<Rigidbody>();

		private readonly Collider[] _overlapResults = (Collider[])(object)new Collider[512];

		private float _lastPlayerRbCacheTime = -999f;

		private float _lastTargetLogTime = -999f;

		private const float PLAYER_RB_CACHE_INTERVAL = 2f;

		private const float FORCE_MULTIPLIER = 80f;

		private const float WAVE_CONE_DOT = -0.55f;

		private int _debugFrameCounter;

		public VoiceForceApplier(IntPtr pointer)
			: base(pointer)
		{
		}

		private void Start()
		{
			_micInput = ((Component)this).GetComponent<MicrophoneInput>();
		}

		private void FixedUpdate()
		{
			//IL_00e0: 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_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: 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_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: 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)
			if ((Object)(object)_micInput == (Object)null || !_micInput.IsWhispering)
			{
				return;
			}
			_debugFrameCounter++;
			if (_debugFrameCounter % 60 == 0)
			{
				MelonLogger.Msg("[VoicePower] Volume=" + _micInput.CurrentVolume.ToString("F3") + " Whisper=" + _micInput.IsWhispering + " Scream=" + _micInput.IsScreaming + " Head=" + ((Object)(object)Player.Head != (Object)null));
			}
			RefreshPlayerRbs();
			Transform head = Player.Head;
			if ((Object)(object)head == (Object)null)
			{
				return;
			}
			Vector3 val = head.position + head.forward * 0.15f;
			float voiceRadius = VoicePowerController.VoiceRadius;
			int num = Physics.OverlapSphereNonAlloc(val, voiceRadius, Il2CppReferenceArray<Collider>.op_Implicit(_overlapResults), -1, (QueryTriggerInteraction)2);
			_waveBodies.Clear();
			for (int i = 0; i < num; i++)
			{
				Rigidbody validRigidbody = GetValidRigidbody(_overlapResults[i]);
				if ((Object)(object)validRigidbody == (Object)null || !_waveBodies.Add(validRigidbody))
				{
					continue;
				}
				Vector3 val2 = validRigidbody.worldCenterOfMass - val;
				float magnitude = ((Vector3)(ref val2)).magnitude;
				if (!(magnitude < 0.01f))
				{
					val2 /= magnitude;
					float num2 = Mathf.Clamp(1f / Mathf.Max(magnitude * magnitude, 0.1f), 0.1f, 5f);
					if (_micInput.IsScreaming)
					{
						float num3 = _micInput.CurrentVolume * 80f * 4f * num2 * VoicePowerController.VoicePowerMultiplier;
						validRigidbody.AddForce(val2 * num3, (ForceMode)1);
					}
					else
					{
						float num4 = _micInput.CurrentVolume * 80f * 2f * num2 * VoicePowerController.VoicePowerMultiplier;
						float num5 = Mathf.Lerp(0.5f, 2f, Mathf.Clamp01(_micInput.LowFrequencyEnergy));
						validRigidbody.AddForce(val2 * (num4 * num5), (ForceMode)1);
					}
				}
			}
		}

		public int ApplyVoiceWave(Vector3 center, Vector3 forward, float radius, float force, float upwardForce)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: 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_0199: 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_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			RefreshPlayerRbs();
			if (((Vector3)(ref forward)).sqrMagnitude < 0.0001f)
			{
				forward = Vector3.forward;
			}
			else
			{
				((Vector3)(ref forward)).Normalize();
			}
			Collider[] array = Il2CppArrayBase<Collider>.op_Implicit((Il2CppArrayBase<Collider>)(object)Physics.OverlapSphere(center, radius, -1, (QueryTriggerInteraction)2));
			int num = ((array != null) ? array.Length : 0);
			_waveBodies.Clear();
			int num2 = 0;
			int num3 = 0;
			int num4 = 0;
			int num5 = 0;
			int num6 = 0;
			for (int i = 0; i < num; i++)
			{
				Collider val = array[i];
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Rigidbody rigidbody = GetRigidbody(val);
				if ((Object)(object)rigidbody == (Object)null)
				{
					num2++;
				}
				else if (rigidbody.isKinematic)
				{
					num3++;
				}
				else if (_playerRbs.Contains(rigidbody))
				{
					num4++;
				}
				else
				{
					if (!VoicePowerController.AffectObjects && IsDevTool(rigidbody))
					{
						continue;
					}
					num5++;
					if (!_waveBodies.Add(rigidbody))
					{
						continue;
					}
					Vector3 val2 = rigidbody.worldCenterOfMass - center;
					float magnitude = ((Vector3)(ref val2)).magnitude;
					if (magnitude < 0.01f || magnitude > radius)
					{
						continue;
					}
					Vector3 val3 = val2 / magnitude;
					float num7 = Vector3.Dot(forward, val3);
					if (!(num7 < -0.55f))
					{
						float num8 = 1f - Mathf.Clamp01(magnitude / radius);
						float num9 = Mathf.Clamp01((num7 - -0.55f) / 1.55f);
						float num10 = force * Mathf.Lerp(0.35f, 1f, num8) * (0.55f + 0.45f * num9);
						if (!(num10 <= 0.01f))
						{
							Vector3 val4 = val3 * num10 + Vector3.up * (upwardForce * num8);
							rigidbody.AddForceAtPosition(val4, rigidbody.worldCenterOfMass, (ForceMode)1);
							num6++;
						}
					}
				}
			}
			LogTargetDiagnostics(num, num2, num3, num4, num5, num6, array);
			return num6;
		}

		public int ApplyShockwave(Vector3 center, float radius, float force)
		{
			//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)
			return ApplyVoiceWave(center, Vector3.forward, radius, force, force * 0.15f);
		}

		private Rigidbody GetRigidbody(Collider collider)
		{
			if ((Object)(object)collider == (Object)null)
			{
				return null;
			}
			Rigidbody attachedRigidbody = collider.attachedRigidbody;
			if ((Object)(object)attachedRigidbody != (Object)null)
			{
				return attachedRigidbody;
			}
			return ((Component)collider).GetComponentInParent<Rigidbody>();
		}

		private Rigidbody GetValidRigidbody(Collider collider)
		{
			Rigidbody rigidbody = GetRigidbody(collider);
			if ((Object)(object)rigidbody == (Object)null || rigidbody.isKinematic || _playerRbs.Contains(rigidbody))
			{
				return null;
			}
			if (!VoicePowerController.AffectObjects && IsDevTool(rigidbody))
			{
				return null;
			}
			return rigidbody;
		}

		private bool IsDevTool(Rigidbody rb)
		{
			if ((Object)(object)((Component)rb).GetComponent("SpawnGun") != (Object)null)
			{
				return true;
			}
			if ((Object)(object)((Component)rb).GetComponent("FlyingGun") != (Object)null)
			{
				return true;
			}
			Transform val = ((Component)rb).transform;
			while ((Object)(object)val != (Object)null)
			{
				if ((Object)(object)((Component)val).GetComponent("SpawnGun") != (Object)null)
				{
					return true;
				}
				if ((Object)(object)((Component)val).GetComponent("FlyingGun") != (Object)null)
				{
					return true;
				}
				val = val.parent;
			}
			return false;
		}

		private void LogTargetDiagnostics(int overlapCount, int noRigidbody, int kinematic, int playerBodies, int candidates, int affected, Collider[] overlapResults)
		{
			float unscaledTime = Time.unscaledTime;
			if (unscaledTime - _lastTargetLogTime < 1f)
			{
				return;
			}
			_lastTargetLogTime = unscaledTime;
			MelonLogger.Msg("[VoicePower] Wave targets: overlaps=" + overlapCount + " candidates=" + candidates + " affected=" + affected + " noRb=" + noRigidbody + " kinematic=" + kinematic + " player=" + playerBodies);
			if (overlapCount <= 0 || affected != 0 || overlapResults == null)
			{
				return;
			}
			_loggedBodies.Clear();
			for (int i = 0; i < overlapResults.Length; i++)
			{
				if (_loggedBodies.Count >= 5)
				{
					break;
				}
				Collider val = overlapResults[i];
				Rigidbody rigidbody = GetRigidbody(val);
				if (!((Object)(object)val == (Object)null) && !((Object)(object)rigidbody == (Object)null) && _loggedBodies.Add(rigidbody))
				{
					MelonLogger.Msg("[VoicePower] Wave target sample: " + ((Object)val).name + " rb=" + ((Object)rigidbody).name + " kinematic=" + rigidbody.isKinematic);
				}
			}
		}

		private void RefreshPlayerRbs()
		{
			float unscaledTime = Time.unscaledTime;
			if (unscaledTime - _lastPlayerRbCacheTime < 2f)
			{
				return;
			}
			_lastPlayerRbCacheTime = unscaledTime;
			_playerRbs.Clear();
			RigManager rigManager = Player.RigManager;
			if ((Object)(object)rigManager == (Object)null || (Object)(object)rigManager.physicsRig == (Object)null)
			{
				return;
			}
			HashSet<Rigidbody> selfRbs = rigManager.physicsRig.selfRbs;
			if (selfRbs == null)
			{
				return;
			}
			Enumerator<Rigidbody> enumerator = selfRbs.GetEnumerator();
			try
			{
				while (enumerator.MoveNext())
				{
					Rigidbody current = enumerator.Current;
					if ((Object)(object)current != (Object)null)
					{
						_playerRbs.Add(current);
					}
				}
			}
			finally
			{
				enumerator.Dispose();
			}
		}
	}
	public class VoicePowerController : MelonMod
	{
		private static MelonPreferences_Category _settingsCategory;

		private static MelonPreferences_Entry<bool> _settingModEnabled;

		private static MelonPreferences_Entry<int> _settingMicDevice;

		private static MelonPreferences_Entry<float> _settingVoicePower;

		private static MelonPreferences_Entry<float> _settingRadius;

		private static MelonPreferences_Entry<bool> _settingAffectObjects;

		private GameObject _micObj;

		private MicrophoneInput _micInput;

		private VoiceForceApplier _forceApplier;

		private ShockwaveEffect _shockwaveEffect;

		private bool _boneMenuCreated;

		private Page _boneMenuPage;

		private Page _micPage;

		private Page _powerPage;

		private Page _radiusPage;

		internal static VoicePowerController Instance { get; private set; }

		internal bool ModEnabled => _settingModEnabled.Value;

		internal static float VoicePowerMultiplier => _settingVoicePower?.Value ?? 1f;

		internal static float VoiceRadius => _settingRadius?.Value ?? 6f;

		internal static bool AffectObjects => _settingAffectObjects?.Value ?? true;

		public override void OnInitializeMelon()
		{
			Instance = this;
			InitSettings();
			MelonLogger.Msg("[VoicePower] VoicePower loaded! Speak to unleash force.");
		}

		public override void OnLateInitializeMelon()
		{
			SetupBoneMenu();
		}

		public override void OnSceneWasLoaded(int levelIndex, string sceneName)
		{
			CleanupObjects();
			if (_settingModEnabled.Value)
			{
				CreateVoicePowerObjects();
			}
		}

		public override void OnApplicationQuit()
		{
			CleanupObjects();
		}

		private void InitSettings()
		{
			_settingsCategory = MelonPreferences.CreateCategory("VoicePower", "VoicePower Settings");
			_settingModEnabled = _settingsCategory.CreateEntry<bool>("ModEnabled", true, "Mod Enabled", "Enable or disable the VoicePower mod.", false, false, (ValueValidator)null, (string)null);
			_settingMicDevice = _settingsCategory.CreateEntry<int>("MicDevice", -1, "Microphone Device", "Index of the microphone to use (-1 = default).", false, false, (ValueValidator)null, (string)null);
			_settingVoicePower = _settingsCategory.CreateEntry<float>("VoicePower", 1f, "Voice Power", "Multiplier for voice force strength (1.0 - 999999).", false, false, (ValueValidator)null, (string)null);
			_settingRadius = _settingsCategory.CreateEntry<float>("Radius", 6f, "Voice Radius", "Radius for voice force detection (0.5 - 999999).", false, false, (ValueValidator)null, (string)null);
			_settingAffectObjects = _settingsCategory.CreateEntry<bool>("AffectObjects", true, "Affect Objects", "Whether voice force affects nearby physics objects.", false, false, (ValueValidator)null, (string)null);
			MelonPreferences.Save();
		}

		private void CreateVoicePowerObjects()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			try
			{
				_micObj = new GameObject("VoicePower_Microphone");
				Object.DontDestroyOnLoad((Object)(object)_micObj);
				_micInput = Il2CppHelper.AddComponent<MicrophoneInput>(_micObj);
				_forceApplier = Il2CppHelper.AddComponent<VoiceForceApplier>(_micObj);
				_shockwaveEffect = Il2CppHelper.AddComponent<ShockwaveEffect>(_micObj);
				Il2CppHelper.AddComponent<VoicePowerOverlay>(_micObj);
				MelonLogger.Msg("[VoicePower] VoicePower objects created.");
			}
			catch (Exception ex)
			{
				MelonLogger.Error("[VoicePower] Failed to create objects: " + ex.Message);
			}
		}

		private void CleanupObjects()
		{
			WindowsMicCapture.Stop();
			_micInput = null;
			_forceApplier = null;
			_shockwaveEffect = null;
			if ((Object)(object)_micObj != (Object)null)
			{
				Object.Destroy((Object)(object)_micObj);
				_micObj = null;
			}
			MelonLogger.Msg("[VoicePower] Cleaned up VoicePower objects.");
		}

		private void SetupBoneMenu()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (_boneMenuCreated)
			{
				return;
			}
			_boneMenuCreated = true;
			try
			{
				_boneMenuPage = Page.Root.CreatePage("VoicePower", new Color(0f, 1f, 0.5f), 0, true);
				RebuildBoneMenu();
				MelonLogger.Msg("[VoicePower] BoneMenu registered.");
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[VoicePower] Failed to setup BoneMenu: " + ex.Message);
			}
		}

		private void RebuildBoneMenu()
		{
			//IL_0029: 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_002e: 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_0074: 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_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: 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)
			if (_boneMenuPage == null)
			{
				return;
			}
			_boneMenuPage.RemoveAll();
			bool value = _settingModEnabled.Value;
			Color val = (value ? Color.green : Color.red);
			string text = (value ? "MOD: ON" : "MOD: OFF");
			_boneMenuPage.CreateFunction(text, val, (Action)delegate
			{
				_settingModEnabled.Value = !_settingModEnabled.Value;
				MelonPreferences.Save();
				RebuildBoneMenu();
				if (!_settingModEnabled.Value)
				{
					CleanupObjects();
				}
				else
				{
					CreateVoicePowerObjects();
				}
			});
			_micPage = _boneMenuPage.CreatePage("Microphones", new Color(0.3f, 0.7f, 1f), 0, true);
			RebuildMicMenu();
			_powerPage = _boneMenuPage.CreatePage("Voice Power", new Color(1f, 0.8f, 0f), 0, true);
			RebuildPowerMenu();
			_radiusPage = _boneMenuPage.CreatePage("Distance", new Color(0.5f, 0.8f, 1f), 0, true);
			RebuildRadiusMenu();
			bool value2 = _settingAffectObjects.Value;
			Color val2 = (value2 ? Color.green : Color.red);
			string text2 = (value2 ? "DEVTOOLS: ON" : "DEVTOOLS: OFF");
			_boneMenuPage.CreateFunction(text2, val2, (Action)delegate
			{
				_settingAffectObjects.Value = !_settingAffectObjects.Value;
				MelonPreferences.Save();
				RebuildBoneMenu();
			});
		}

		private void RebuildMicMenu()
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: 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_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			if (_micPage == null)
			{
				return;
			}
			_micPage.RemoveAll();
			(int, string)[] availableDevices = WindowsMicCapture.GetAvailableDevices();
			int value = _settingMicDevice.Value;
			Color val = ((value < 0) ? Color.green : Color.white);
			string text = ((value < 0) ? "> Default" : "Default");
			_micPage.CreateFunction(text, val, (Action)delegate
			{
				_settingMicDevice.Value = -1;
				MelonPreferences.Save();
				RestartMic();
				RebuildMicMenu();
			});
			(int, string)[] array = availableDevices;
			for (int num = 0; num < array.Length; num++)
			{
				(int, string) tuple = array[num];
				int devIdx = tuple.Item1;
				string item = tuple.Item2;
				bool flag = value == devIdx;
				Color val2 = (flag ? Color.green : Color.white);
				string text2 = (flag ? ("> " + item) : item);
				_micPage.CreateFunction(text2, val2, (Action)delegate
				{
					_settingMicDevice.Value = devIdx;
					MelonPreferences.Save();
					RestartMic();
					RebuildMicMenu();
				});
			}
			if (availableDevices.Length == 0)
			{
				_micPage.CreateFunction("No devices found", Color.red, (Action)delegate
				{
				});
			}
		}

		private void RebuildPowerMenu()
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			if (_powerPage == null)
			{
				return;
			}
			_powerPage.RemoveAll();
			string text = "CURRENT: " + _settingVoicePower.Value.ToString("F1") + "x";
			_powerPage.CreateFunction(text, Color.yellow, (Action)delegate
			{
			});
			float[] array = new float[5] { 0.1f, 1f, 10f, 100f, 1000f };
			float[] array2 = array;
			for (int num = 0; num < array2.Length; num++)
			{
				float num2 = array2[num];
				string text2 = ((num2 >= 1f) ? num2.ToString("F0") : num2.ToString("F1"));
				float s = num2;
				_powerPage.CreateFunction("[+] " + text2, Color.green, (Action)delegate
				{
					_settingVoicePower.Value = Mathf.Min(_settingVoicePower.Value + s, 999999f);
					MelonPreferences.Save();
					RebuildPowerMenu();
				});
				_powerPage.CreateFunction("[-] " + text2, Color.red, (Action)delegate
				{
					_settingVoicePower.Value = Mathf.Max(_settingVoicePower.Value - s, 1f);
					MelonPreferences.Save();
					RebuildPowerMenu();
				});
			}
		}

		private void RebuildRadiusMenu()
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			if (_radiusPage == null)
			{
				return;
			}
			_radiusPage.RemoveAll();
			string text = "CURRENT: " + _settingRadius.Value.ToString("F1") + "m";
			_radiusPage.CreateFunction(text, Color.yellow, (Action)delegate
			{
			});
			float[] array = new float[5] { 0.1f, 1f, 10f, 100f, 1000f };
			float[] array2 = array;
			for (int num = 0; num < array2.Length; num++)
			{
				float num2 = array2[num];
				string text2 = ((num2 >= 1f) ? num2.ToString("F0") : num2.ToString("F1"));
				float s = num2;
				_radiusPage.CreateFunction("[+] " + text2, Color.green, (Action)delegate
				{
					_settingRadius.Value = Mathf.Min(_settingRadius.Value + s, 999999f);
					MelonPreferences.Save();
					RebuildRadiusMenu();
				});
				_radiusPage.CreateFunction("[-] " + text2, Color.red, (Action)delegate
				{
					_settingRadius.Value = Mathf.Max(_settingRadius.Value - s, 0.5f);
					MelonPreferences.Save();
					RebuildRadiusMenu();
				});
			}
		}

		private void RestartMic()
		{
			if (!_settingModEnabled.Value)
			{
				return;
			}
			CleanupObjects();
			CreateVoicePowerObjects();
			string text = "Default";
			int value = _settingMicDevice.Value;
			if (value >= 0)
			{
				(int, string)[] availableDevices = WindowsMicCapture.GetAvailableDevices();
				for (int i = 0; i < availableDevices.Length; i++)
				{
					(int, string) tuple = availableDevices[i];
					if (tuple.Item1 == value)
					{
						text = tuple.Item2;
						break;
					}
				}
			}
			MelonLogger.Msg("[VoicePower] Switched mic to: " + text);
		}
	}
	[RegisterTypeInIl2Cpp]
	public class VoicePowerOverlay : MonoBehaviour
	{
		private MicrophoneInput _micInput;

		private Canvas _canvas;

		private GameObject _canvasObj;

		private Image _fillImage;

		private Image _bgImage;

		private Image _glowImage;

		private Text _label;

		private const float CANVAS_WIDTH = 0.01f;

		private const float CANVAS_HEIGHT = 0.1f;

		private const float OFFSET_Y = -0.07f;

		private const float OFFSET_X = -0.06f;

		private const float OFFSET_Z = 0.3f;

		private float _smoothFill;

		private float _smoothVelocity;

		private float _smoothGlow;

		private float _smoothGlowVelocity;

		private RectTransform _fillRect;

		private RectTransform _glowRect;

		private static readonly Color cGreen = new Color(0.15f, 0.85f, 0.3f, 1f);

		private static readonly Color cYellow = new Color(1f, 0.85f, 0.15f, 1f);

		private static readonly Color cRed = new Color(0.95f, 0.2f, 0.15f, 1f);

		private static readonly Color cGlowIdle = new Color(0.15f, 0.85f, 0.3f, 0f);

		private static readonly Color cGlowHot = new Color(1f, 0.5f, 0.15f, 0.45f);

		public VoicePowerOverlay(IntPtr pointer)
			: base(pointer)
		{
		}

		private void Start()
		{
			CreateOverlay();
			_micInput = ((Component)this).GetComponent<MicrophoneInput>();
			if ((Object)(object)_micInput == (Object)null)
			{
				MelonLogger.Warning("[VoicePower] VoicePowerOverlay: MicrophoneInput not found on same GameObject!");
			}
		}

		private static Sprite MakeRoundedSprite(int w, int h, int radius)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Expected O, but got Unknown
			//IL_00e2: 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_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = new Texture2D(w, h, (TextureFormat)4, false);
			Color[] array = (Color[])(object)new Color[w * h];
			for (int i = 0; i < h; i++)
			{
				for (int j = 0; j < w; j++)
				{
					float num = Mathf.Max(new int[3]
					{
						radius - j,
						j - (w - 1 - radius),
						0
					});
					float num2 = Mathf.Max(new int[3]
					{
						radius - i,
						i - (h - 1 - radius),
						0
					});
					float num3 = Mathf.Sqrt(num * num + num2 * num2) - (float)radius;
					float num4 = Mathf.Clamp01(0.5f - num3);
					array[i * w + j] = new Color(1f, 1f, 1f, num4);
				}
			}
			val.SetPixels(Il2CppStructArray<Color>.op_Implicit(array));
			val.Apply(false, false);
			((Texture)val).filterMode = (FilterMode)1;
			return Sprite.Create(val, new Rect(0f, 0f, (float)w, (float)h), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0, new Vector4((float)radius, (float)radius, (float)radius, (float)radius));
		}

		private static Sprite MakeShadowSprite(int w, int h, int radius)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			//IL_011b: 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_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			int num = 6;
			int num2 = w + num * 2;
			int num3 = h + num * 2;
			Texture2D val = new Texture2D(num2, num3, (TextureFormat)4, false);
			Color[] array = (Color[])(object)new Color[num2 * num3];
			for (int i = 0; i < num3; i++)
			{
				for (int j = 0; j < num2; j++)
				{
					float num4 = Mathf.Max(new int[3]
					{
						radius + num - j,
						j - (num2 - 1 - (radius + num)),
						0
					});
					float num5 = Mathf.Max(new int[3]
					{
						radius + num - i,
						i - (num3 - 1 - (radius + num)),
						0
					});
					float num6 = Mathf.Sqrt(num4 * num4 + num5 * num5) - (float)(radius + num);
					float num7 = Mathf.Clamp01(0.35f - num6 * 0.12f);
					array[i * num2 + j] = new Color(0f, 0f, 0f, Mathf.Max(0f, num7));
				}
			}
			val.SetPixels(Il2CppStructArray<Color>.op_Implicit(array));
			val.Apply(false, false);
			((Texture)val).filterMode = (FilterMode)1;
			return Sprite.Create(val, new Rect(0f, 0f, (float)num2, (float)num3), new Vector2(0.5f, 0.5f), 100f);
		}

		private void CreateOverlay()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			//IL_0054: 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_009a: Expected O, but got Unknown
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: 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_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Expected O, but got Unknown
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: 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_01ed: 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_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Expected O, but got Unknown
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ea: Expected O, but got Unknown
			//IL_0322: Unknown result type (might be due to invalid IL or missing references)
			//IL_0361: 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_038b: Unknown result type (might be due to invalid IL or missing references)
			//IL_039b: Unknown result type (might be due to invalid IL or missing references)
			//IL_03aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b1: Expected O, but got Unknown
			//IL_0409: Unknown result type (might be due to invalid IL or missing references)
			//IL_0444: Unknown result type (might be due to invalid IL or missing references)
			//IL_045a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0466: Unknown result type (might be due to invalid IL or missing references)
			//IL_0472: Unknown result type (might be due to invalid IL or missing references)
			//IL_0487: Unknown result type (might be due to invalid IL or missing references)
			//IL_0491: Unknown result type (might be due to invalid IL or missing references)
			_canvasObj = new GameObject("VoicePower_OverlayCanvas");
			_canvas = Il2CppHelper.AddComponent<Canvas>(_canvasObj);
			_canvas.renderMode = (RenderMode)2;
			_canvas.sortingOrder = 32767;
			RectTransform component = _canvasObj.GetComponent<RectTransform>();
			component.sizeDelta = new Vector2(20f, 200f);
			CanvasScaler val = Il2CppHelper.AddComponent<CanvasScaler>(_canvasObj);
			val.dynamicPixelsPerUnit = 100f;
			Il2CppHelper.AddComponent<GraphicRaycaster>(_canvasObj);
			Sprite sprite = MakeShadowSprite(20, 200, 8);
			GameObject val2 = new GameObject("Shadow");
			val2.transform.SetParent(_canvasObj.transform, false);
			Image val3 = Il2CppHelper.AddComponent<Image>(val2);
			val3.sprite = sprite;
			((Graphic)val3).color = new Color(0f, 0f, 0f, 0.3f);
			RectTransform component2 = val2.GetComponent<RectTransform>();
			component2.anchorMin = new Vector2(0f, 0f);
			component2.anchorMax = new Vector2(1f, 1f);
			component2.offsetMin = new Vector2(-3f, -3f);
			component2.offsetMax = new Vector2(3f, 3f);
			Sprite sprite2 = MakeRoundedSprite(20, 200, 8);
			GameObject val4 = new GameObject("Bar_BG");
			val4.transform.SetParent(_canvasObj.transform, false);
			_bgImage = Il2CppHelper.AddComponent<Image>(val4);
			_bgImage.sprite = sprite2;
			((Graphic)_bgImage).color = new Color(0.08f, 0.08f, 0.12f, 0.7f);
			_bgImage.type = (Type)1;
			_bgImage.preserveAspect = false;
			RectTransform component3 = val4.GetComponent<RectTransform>();
			component3.anchorMin = Vector2.zero;
			component3.anchorMax = Vector2.one;
			component3.offsetMin = Vector2.zero;
			component3.offsetMax = Vector2.zero;
			Sprite sprite3 = MakeRoundedSprite(20, 200, 8);
			GameObject val5 = new GameObject("Bar_Glow");
			val5.transform.SetParent(_canvasObj.transform, false);
			_glowImage = Il2CppHelper.AddComponent<Image>(val5);
			_glowImage.sprite = sprite3;
			((Graphic)_glowImage).color = cGlowIdle;
			_glowImage.type = (Type)1;
			_glowImage.preserveAspect = false;
			_glowRect = val5.GetComponent<RectTransform>();
			_glowRect.anchorMin = Vector2.zero;
			_glowRect.anchorMax = new Vector2(1f, 0f);
			_glowRect.offsetMin = Vector2.zero;
			_glowRect.offsetMax = Vector2.zero;
			Sprite sprite4 = MakeRoundedSprite(20, 200, 8);
			GameObject val6 = new GameObject("Bar_Fill");
			val6.transform.SetParent(_canvasObj.transform, false);
			_fillImage = Il2CppHelper.AddComponent<Image>(val6);
			_fillImage.sprite = sprite4;
			((Graphic)_fillImage).color = cGreen;
			_fillImage.type = (Type)1;
			_fillImage.preserveAspect = false;
			_fillRect = val6.GetComponent<RectTransform>();
			_fillRect.anchorMin = new Vector2(0f, 0f);
			_fillRect.anchorMax = new Vector2(1f, 0f);
			_fillRect.offsetMin = Vector2.zero;
			_fillRect.offsetMax = Vector2.zero;
			GameObject val7 = new GameObject("Label");
			val7.transform.SetParent(_canvasObj.transform, false);
			_label = Il2CppHelper.AddComponent<Text>(val7);
			_label.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
			_label.fontSize = 7;
			_label.alignment = (TextAnchor)4;
			((Graphic)_label).color = Color.white;
			_label.text = "";
			_label.horizontalOverflow = (HorizontalWrapMode)1;
			RectTransform component4 = val7.GetComponent<RectTransform>();
			component4.anchorMin = new Vector2(0f, -0.3f);
			component4.anchorMax = new Vector2(1f, 0f);
			component4.offsetMin = Vector2.zero;
			component4.offsetMax = Vector2.zero;
			_canvasObj.transform.localScale = Vector3.one * 0.0005f;
		}

		private void LateUpdate()
		{
			//IL_0062: 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_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_007d: Unknown result type (might be due to invalid IL or missing references)
			//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_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: 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_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: 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_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cf: 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_0286: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_micInput == (Object)null || (Object)(object)_canvasObj == (Object)null || (Object)(object)_fillImage == (Object)null || (Object)(object)_label == (Object)null)
			{
				return;
			}
			Transform head = Player.Head;
			if ((Object)(object)head == (Object)null)
			{
				_canvasObj.SetActive(false);
				return;
			}
			_canvasObj.SetActive(true);
			Vector3 position = head.position + head.forward * 0.3f + head.up * -0.07f + head.right * -0.06f;
			_canvasObj.transform.position = position;
			_canvasObj.transform.rotation = Quaternion.LookRotation(head.forward, head.up);
			float currentVolume = _micInput.CurrentVolume;
			float num = Mathf.Clamp01(currentVolume * 10f);
			_smoothFill = Mathf.SmoothDamp(_smoothFill, num, ref _smoothVelocity, 0.06f);
			float num2 = Mathf.Max(0.005f, _smoothFill);
			_fillRect.anchorMax = new Vector2(1f, num2);
			_glowRect.anchorMax = new Vector2(1f, Mathf.Min(1f, num2 * 1.35f));
			Color color = VolumeToGradient(_smoothFill);
			((Graphic)_fillImage).color = color;
			float num3 = Mathf.Clamp01(currentVolume * 8f);
			_smoothGlow = Mathf.SmoothDamp(_smoothGlow, num3, ref _smoothGlowVelocity, 0.1f);
			Color color2 = Color.Lerp(cGlowIdle, cGlowHot, _smoothGlow);
			color2.a *= 0.5f + _smoothGlow * 0.5f;
			((Graphic)_glowImage).color = color2;
			if (_micInput.IsScreaming)
			{
				_label.text = "SCREAM!";
				((Graphic)_label).color = Color.Lerp(cYellow, Color.red, 0.5f + Mathf.Sin(Time.time * 12f) * 0.5f);
			}
			else if (_micInput.HasSound)
			{
				float soundIntensity = _micInput.SoundIntensity;
				_label.text = ((soundIntensity > 0.75f) ? "LOUD" : "WAVE");
				((Graphic)_label).color = Color.Lerp(Color.white, cYellow, soundIntensity);
			}
			else
			{
				_label.text = (_micInput.IsMicrophoneActive ? "MIC OK" : "MIC OFF");
				((Graphic)_label).color = new Color(1f, 1f, 1f, 0.7f);
			}
		}

		private static Color VolumeToGradient(float t)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			t = Mathf.Clamp01(t);
			if (t < 0.5f)
			{
				return Color.Lerp(cGreen, cYellow, t * 2f);
			}
			return Color.Lerp(cYellow, cRed, (t - 0.5f) * 2f);
		}

		private void OnDestroy()
		{
			if ((Object)(object)_canvasObj != (Object)null)
			{
				Object.Destroy((Object)(object)_canvasObj);
			}
		}
	}
	internal static class WindowsMicCapture
	{
		private delegate void WaveInProc(IntPtr hWaveIn, uint uMsg, IntPtr dwInstance, IntPtr dwParam1, IntPtr dwParam2);

		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
		private struct WAVEINCAPS
		{
			public ushort wMid;

			public ushort wPid;

			public uint vDriverVersion;

			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
			public string szPname;

			public uint dwFormats;

			public ushort wChannels;

			public ushort wReserved1;
		}

		private struct WAVEFORMATEX
		{
			public ushort wFormatTag;

			public ushort nChannels;

			public uint nSamplesPerSec;

			public uint nAvgBytesPerSec;

			public ushort nBlockAlign;

			public ushort wBitsPerSample;

			public ushort cbSize;
		}

		private struct WAVEHDR
		{
			public IntPtr lpData;

			public int dwBufferLength;

			public int dwBytesRecorded;

			public IntPtr dwUser;

			public int dwFlags;

			public int dwLoops;

			public IntPtr lpNext;

			public IntPtr reserved;
		}

		private const ushort WAVE_FORMAT_PCM = 1;

		private const uint CALLBACK_FUNCTION = 196608u;

		private const uint WAVE_MAPPER = uint.MaxValue;

		private const uint MM_WIM_OPEN = 958u;

		private const uint MM_WIM_CLOSE = 959u;

		private const uint MM_WIM_DATA = 960u;

		private const int MMSYSERR_NOERROR = 0;

		private const int MMSYSERR_NOTSUPPORTED = 8;

		private const int WAVERR_BADFORMAT = 32;

		private const int INTERNAL_SETUP_ERROR = 10000;

		private static WaveInProc _waveInProc;

		private static GCHandle _delegateHandle;

		private static IntPtr _hWaveIn;

		private static bool _isRecording;

		private static readonly object _lock = new object();

		private static float[] _ringBuffer = new float[16384];

		private static int _writePos;

		private static int _readPos;

		private static int _availableSamples;

		private const int RING_SIZE = 16384;

		private const int NUM_BUFFERS = 4;

		private const int BUFFER_SIZE_BYTES = 4096;

		private const int MAX_BUFFER_SAMPLES = 2048;

		private static readonly IntPtr[] _bufferPointers = new IntPtr[4];

		private static readonly IntPtr[] _headerPointers = new IntPtr[4];

		private static readonly bool[] _preparedHeaders = new bool[4];

		private static readonly short[] _conversionBuffer = new short[2048];

		private static int _callbackCount;

		private static int _callbackErrorCount;

		public static int SampleRate { get; private set; } = 44100;

		public static int Channels { get; private set; } = 1;

		public static int SelectedDeviceIndex { get; private set; } = -1;

		public static bool IsRecording => _isRecording;

		public static int CallbackCount => _callbackCount;

		[DllImport("winmm.dll")]
		private static extern int waveInGetNumDevs();

		[DllImport("winmm.dll", CharSet = CharSet.Unicode)]
		private static extern int waveInGetDevCaps(IntPtr uDeviceID, out WAVEINCAPS pwic, int cbwic);

		[DllImport("winmm.dll")]
		private static extern int waveInOpen(out IntPtr phwi, uint uDeviceID, ref WAVEFORMATEX pwfx, IntPtr dwCallback, IntPtr dwInstance, uint fdwOpen);

		[DllImport("winmm.dll")]
		private static extern int waveInPrepareHeader(IntPtr hwi, IntPtr pwh, int cbwh);

		[DllImport("winmm.dll")]
		private static extern int waveInUnprepareHeader(IntPtr hwi, IntPtr pwh, int cbwh);

		[DllImport("winmm.dll")]
		private static extern int waveInAddBuffer(IntPtr hwi, IntPtr pwh, int cbwh);

		[DllImport("winmm.dll")]
		private static extern int waveInStart(IntPtr hwi);

		[DllImport("winmm.dll")]
		private static extern int waveInStop(IntPtr hwi);

		[DllImport("winmm.dll")]
		private static extern int waveInReset(IntPtr hwi);

		[DllImport("winmm.dll")]
		private static extern int waveInClose(IntPtr hwi);

		public static int AvailableSamples()
		{
			lock (_lock)
			{
				return _availableSamples;
			}
		}

		public static (int index, string name)[] GetAvailableDevices()
		{
			int num = waveInGetNumDevs();
			List<(int, string)> list = new List<(int, string)>();
			for (int i = 0; i < num; i++)
			{
				if (waveInGetDevCaps((IntPtr)i, out var pwic, Marshal.SizeOf<WAVEINCAPS>()) == 0)
				{
					list.Add((i, pwic.szPname ?? "Unnamed device"));
				}
			}
			return list.ToArray();
		}

		public static bool Start(int sampleRate = 44100, int channels = 1, int deviceIndex = -1)
		{
			Stop();
			lock (_lock)
			{
				_ringBuffer = new float[16384];
				_writePos = 0;
				_readPos = 0;
				_availableSamples = 0;
			}
			_callbackCount = 0;
			_callbackErrorCount = 0;
			SampleRate = sampleRate;
			Channels = channels;
			MelonLogger.Msg("[VoicePower] WindowsMicCapture.Start() deviceIndex=" + deviceIndex);
			int num = waveInGetNumDevs();
			MelonLogger.Msg("[VoicePower] waveInGetNumDevs() = " + num);
			if (num == 0)
			{
				MelonLogger.Error("[VoicePower] No Windows waveIn input devices found.");
				return false;
			}
			for (int i = 0; i < num; i++)
			{
				WAVEINCAPS pwic;
				int num2 = waveInGetDevCaps((IntPtr)i, out pwic, Marshal.SizeOf<WAVEINCAPS>());
				if (num2 == 0)
				{
					MelonLogger.Msg("[VoicePower] Device " + i + ": " + (pwic.szPname ?? "Unnamed") + " channels=" + pwic.wChannels);
				}
				else
				{
					MelonLogger.Warning("[VoicePower] waveInGetDevCaps(" + i + ") failed: " + num2 + " (" + DescribeError(num2) + ")");
				}
			}
			if (deviceIndex < 0 || deviceIndex >= num)
			{
				if (deviceIndex != -1)
				{
					MelonLogger.Warning("[VoicePower] Device index " + deviceIndex + " is invalid; using WAVE_MAPPER.");
				}
				deviceIndex = -1;
			}
			SelectedDeviceIndex = deviceIndex;
			_waveInProc = WaveInCallback;
			_delegateHandle = GCHandle.Alloc(_waveInProc);
			IntPtr functionPointerForDelegate = Marshal.GetFunctionPointerForDelegate(_waveInProc);
			uint deviceId = ((deviceIndex >= 0) ? ((uint)deviceIndex) : uint.MaxValue);
			MelonLogger.Msg("[VoicePower] Selected waveIn deviceId=" + deviceId + " (0x" + deviceId.ToString("X8") + ")");
			int[] array = ((sampleRate != 48000) ? new int[2] { sampleRate, 48000 } : new int[1] { 48000 });
			for (int j = 0; j < array.Length; j++)
			{
				int sampleRate2 = array[j];
				int num3 = TryOpenAndStart(deviceId, sampleRate2, channels, functionPointerForDelegate);
				if (num3 == 0)
				{
					SampleRate = sampleRate2;
					Channels = channels;
					MelonLogger.Msg("[VoicePower] Mic started: " + GetDeviceName(deviceIndex) + " (" + sampleRate2 + "Hz, " + channels + "ch, 16bit)");
					return true;
				}
				MelonLogger.Warning("[VoicePower] Capture format " + sampleRate2 + "Hz failed: " + num3 + " (" + DescribeError(num3) + ")");
				if (num3 != 32 && num3 != 8)
				{
					break;
				}
			}
			ReleaseDelegate();
			_isRecording = false;
			return false;
		}

		private static int TryOpenAndStart(uint deviceId, int sampleRate, int channels, IntPtr callbackPointer)
		{
			WAVEFORMATEX pwfx = new WAVEFORMATEX
			{
				wFormatTag = 1,
				nChannels = (ushort)channels,
				nSamplesPerSec = (uint)sampleRate,
				nAvgBytesPerSec = (uint)(sampleRate * channels * 2),
				nBlockAlign = (ushort)(channels * 2),
				wBitsPerSample = 16,
				cbSize = 0
			};
			MelonLogger.Msg("[VoicePower] waveInOpen: " + sampleRate + "Hz " + channels + "ch 16bit");
			IntPtr phwi;
			int num = waveInOpen(out phwi, deviceId, ref pwfx, callbackPointer, IntPtr.Zero, 196608u);
			if (num != 0)
			{
				MelonLogger.Error("[VoicePower] waveInOpen FAILED: " + num + " (" + DescribeError(num) + ")");
				return num;
			}
			_hWaveIn = phwi;
			MelonLogger.Msg("[VoicePower] waveInOpen OK, handle=0x" + phwi.ToString("X"));
			for (int i = 0; i < 4; i++)
			{
				_bufferPointers[i] = Marshal.AllocHGlobal(4096);
				_headerPointers[i] = Marshal.AllocHGlobal(Marshal.SizeOf<WAVEHDR>());
				WAVEHDR structure = new WAVEHDR
				{
					lpData = _bufferPointers[i],
					dwBufferLength = 4096,
					dwBytesRecorded = 0
				};
				Marshal.StructureToPtr(structure, _headerPointers[i], fDeleteOld: false);
				int num2 = waveInPrepareHeader(_hWaveIn, _headerPointers[i], Marshal.SizeOf<WAVEHDR>());
				if (num2 != 0)
				{
					MelonLogger.Error("[VoicePower] Buffer " + i + " prepare failed: " + num2 + " (" + DescribeError(num2) + ")");
					Stop();
					return 10000 + num2;
				}
				_preparedHeaders[i] = true;
				int num3 = waveInAddBuffer(_hWaveIn, _headerPointers[i], Marshal.SizeOf<WAVEHDR>());
				if (num3 != 0)
				{
					MelonLogger.Error("[VoicePower] Buffer " + i + " add failed: " + num3 + " (" + DescribeError(num3) + ")");
					Stop();
					return 10000 + num3;
				}
				MelonLogger.Msg("[VoicePower] Buffer " + i + " prepared and added");
			}
			_isRecording = true;
			MelonLogger.Msg("[VoicePower] Calling waveInStart...");
			int num4 = waveInStart(_hWaveIn);
			if (num4 != 0)
			{
				MelonLogger.Error("[VoicePower] waveInStart FAILED: " + num4 + " (" + DescribeError(num4) + ")");
				Stop();
				return 10000 + num4;
			}
			MelonLogger.Msg("[VoicePower] waveInStart OK; waiting for MM_WIM_DATA callbacks");
			return 0;
		}

		public static void Stop()
		{
			_isRecording = false;
			if (_hWaveIn != IntPtr.Zero)
			{
				int num = waveInReset(_hWaveIn);
				if (num != 0)
				{
					MelonLogger.Warning("[VoicePower] waveInReset returned " + num);
				}
				int num2 = waveInStop(_hWaveIn);
				if (num2 != 0)
				{
					MelonLogger.Warning("[VoicePower] waveInStop returned " + num2);
				}
				for (int i = 0; i < 4; i++)
				{
					if (_preparedHeaders[i] && _headerPointers[i] != IntPtr.Zero)
					{
						int num3 = waveInUnprepareHeader(_hWaveIn, _headerPointers[i], Marshal.SizeOf<WAVEHDR>());
						if (num3 != 0)
						{
							MelonLogger.Warning("[VoicePower] Buffer " + i + " unprepare returned " + num3);
						}
					}
					_preparedHeaders[i] = false;
				}
				int num4 = waveInClose(_hWaveIn);
				if (num4 != 0)
				{
					MelonLogger.Warning("[VoicePower] waveInClose returned " + num4);
				}
				_hWaveIn = IntPtr.Zero;
			}
			FreeNativeBuffers();
			ReleaseDelegate();
			lock (_lock)
			{
				_readPos = _writePos;
				_availableSamples = 0;
			}
		}

		private static void FreeNativeBuffers()
		{
			for (int i = 0; i < 4; i++)
			{
				if (_headerPointers[i] != IntPtr.Zero)
				{
					Marshal.FreeHGlobal(_headerPointers[i]);
					_headerPointers[i] = IntPtr.Zero;
				}
				if (_bufferPointers[i] != IntPtr.Zero)
				{
					Marshal.FreeHGlobal(_bufferPointers[i]);
					_bufferPointers[i] = IntPtr.Zero;
				}
				_preparedHeaders[i] = false;
			}
		}

		private static void ReleaseDelegate()
		{
			if (_delegateHandle.IsAllocated)
			{
				_delegateHandle.Free();
			}
			_waveInProc = null;
		}

		private static void WaveInCallback(IntPtr hWaveIn, uint message, IntPtr dwInstance, IntPtr dwParam1, IntPtr dwParam2)
		{
			switch (message)
			{
			case 958u:
			case 959u:
				MelonLogger.Msg("[VoicePower] waveIn callback message=0x" + message.ToString("X4"));
				break;
			default:
				MelonLogger.Warning("[VoicePower] Unexpected waveIn callback message=0x" + message.ToString("X4"));
				break;
			case 960u:
				if (!_isRecording || dwParam1 == IntPtr.Zero)
				{
					break;
				}
				try
				{
					WAVEHDR wAVEHDR = Marshal.PtrToStructure<WAVEHDR>(dwParam1);
					int num = wAVEHDR.dwBytesRecorded / 2;
					if (num <= 0)
					{
						RequeueBuffer(hWaveIn, dwParam1);
						break;
					}
					if (num > _conversionBuffer.Length)
					{
						num = _conversionBuffer.Length;
					}
					Marshal.Copy(wAVEHDR.lpData, _conversionBuffer, 0, num);
					lock (_lock)
					{
						for (int i = 0; i < num; i++)
						{
							if (_availableSamples == 16384)
							{
								_readPos = (_readPos + 1) % 16384;
								_availableSamples--;
							}
							_ringBuffer[_writePos] = (float)_conversionBuffer[i] / 32768f;
							_writePos = (_writePos + 1) % 16384;
							_availableSamples++;
						}
					}
					_callbackCount++;
					if (_callbackCount <= 3 || _callbackCount % 50 == 0)
					{
						MelonLogger.Msg("[VoicePower] MM_WIM_DATA #" + _callbackCount + " samples=" + num + " bytes=" + wAVEHDR.dwBytesRecorded + " available=" + AvailableSamples());
					}
					RequeueBuffer(hWaveIn, dwParam1);
					break;
				}
				catch (Exception ex)
				{
					_callbackErrorCount++;
					MelonLogger.Error("[VoicePower] Mic callback error #" + _callbackErrorCount + ": " + ex);
					break;
				}
			}
		}

		private static void RequeueBuffer(IntPtr hWaveIn, IntPtr headerPointer)
		{
			int bufferIndex = GetBufferIndex(headerPointer);
			if (bufferIndex < 0 || bufferIndex >= 4 || !_preparedHeaders[bufferIndex])
			{
				MelonLogger.Error("[VoicePower] Could not identify completed waveIn buffer");
				return;
			}
			int num = waveInAddBuffer(hWaveIn, _headerPointers[bufferIndex], Marshal.SizeOf<WAVEHDR>());
			if (num != 0)
			{
				MelonLogger.Error("[VoicePower] Re-adding buffer " + bufferIndex + " failed: " + num + " (" + DescribeError(num) + ")");
			}
		}

		private static int GetBufferIndex(IntPtr headerPointer)
		{
			for (int i = 0; i < 4; i++)
			{
				if (_headerPointers[i] == headerPointer)
				{
					return i;
				}
			}
			return -1;
		}

		public static int ReadSamples(float[] destination, int maxSamples)
		{
			if (destination == null || maxSamples <= 0)
			{
				return 0;
			}
			int i = 0;
			lock (_lock)
			{
				for (int num = Math.Min(maxSamples, destination.Length); i < num; i++)
				{
					if (_availableSamples <= 0)
					{
						break;
					}
					destination[i] = _ringBuffer[_readPos];
					_readPos = (_readPos + 1) % 16384;
					_availableSamples--;
				}
			}
			return i;
		}

		public static void Flush()
		{
			lock (_lock)
			{
				_readPos = _writePos;
				_availableSamples = 0;
			}
		}

		private static string GetDeviceName(int deviceIndex)
		{
			if (deviceIndex < 0)
			{
				return "Default/WAVE_MAPPER";
			}
			if (waveInGetDevCaps((IntPtr)deviceIndex, out var pwic, Marshal.SizeOf<WAVEINCAPS>()) == 0 && !string.IsNullOrEmpty(pwic.szPname))
			{
				return pwic.szPname;
			}
			return "Device " + deviceIndex;
		}

		private static string DescribeError(int error)
		{
			return error switch
			{
				0 => "NOERROR", 
				1 => "MMSYSERR_ERROR", 
				2 => "MMSYSERR_BADDEVICEID", 
				4 => "MMSYSERR_ALLOCATED", 
				6 => "MMSYSERR_NODRIVER", 
				7 => "MMSYSERR_NOMEM", 
				8 => "MMSYSERR_NOTSUPPORTED", 
				10 => "MMSYSERR_INVALFLAG", 
				11 => "MMSYSERR_INVALPARAM", 
				32 => "WAVERR_BADFORMAT", 
				33 => "WAVERR_STILLPLAYING", 
				34 => "WAVERR_UNPREPARED", 
				35 => "WAVERR_SYNC", 
				10000 => "internal setup failure", 
				_ => "WinMM error", 
			};
		}
	}
}