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(GameObject go) where T : Component { try { return go.AddComponent(); } catch (TypeInitializationException) { MelonLogger.Warning("[VoicePower] Generic AddComponent failed for " + typeof(T).Name + ", using reflection fallback"); return AddComponentViaReflection(go); } catch (Exception ex2) { MelonLogger.Error("[VoicePower] AddComponent failed for " + typeof(T).Name + ": " + ex2.Message); return default(T); } } private static T AddComponentViaReflection(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(); 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 entry = category.GetEntry("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 _activeRings = new List(); 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(); _forceApplier = ((Component)this).GetComponent(); 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(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(_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.op_Implicit((Burst[])(object)new Burst[1] { new Burst(0f, MinMaxCurve.op_Implicit(80f)) })); ParticleSystemRenderer component = _particleObj.GetComponent(); 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 _playerRbs = new HashSet(); private readonly HashSet _waveBodies = new HashSet(); private readonly HashSet _loggedBodies = new HashSet(); 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(); } 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.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.op_Implicit((Il2CppArrayBase)(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(); } 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 selfRbs = rigManager.physicsRig.selfRbs; if (selfRbs == null) { return; } Enumerator 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 _settingModEnabled; private static MelonPreferences_Entry _settingMicDevice; private static MelonPreferences_Entry _settingVoicePower; private static MelonPreferences_Entry _settingRadius; private static MelonPreferences_Entry _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("ModEnabled", true, "Mod Enabled", "Enable or disable the VoicePower mod.", false, false, (ValueValidator)null, (string)null); _settingMicDevice = _settingsCategory.CreateEntry("MicDevice", -1, "Microphone Device", "Index of the microphone to use (-1 = default).", false, false, (ValueValidator)null, (string)null); _settingVoicePower = _settingsCategory.CreateEntry("VoicePower", 1f, "Voice Power", "Multiplier for voice force strength (1.0 - 999999).", false, false, (ValueValidator)null, (string)null); _settingRadius = _settingsCategory.CreateEntry("Radius", 6f, "Voice Radius", "Radius for voice force detection (0.5 - 999999).", false, false, (ValueValidator)null, (string)null); _settingAffectObjects = _settingsCategory.CreateEntry("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(_micObj); _forceApplier = Il2CppHelper.AddComponent(_micObj); _shockwaveEffect = Il2CppHelper.AddComponent(_micObj); Il2CppHelper.AddComponent(_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(); 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.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.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(_canvasObj); _canvas.renderMode = (RenderMode)2; _canvas.sortingOrder = 32767; RectTransform component = _canvasObj.GetComponent(); component.sizeDelta = new Vector2(20f, 200f); CanvasScaler val = Il2CppHelper.AddComponent(_canvasObj); val.dynamicPixelsPerUnit = 100f; Il2CppHelper.AddComponent(_canvasObj); Sprite sprite = MakeShadowSprite(20, 200, 8); GameObject val2 = new GameObject("Shadow"); val2.transform.SetParent(_canvasObj.transform, false); Image val3 = Il2CppHelper.AddComponent(val2); val3.sprite = sprite; ((Graphic)val3).color = new Color(0f, 0f, 0f, 0.3f); RectTransform component2 = val2.GetComponent(); 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(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(); 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(val5); _glowImage.sprite = sprite3; ((Graphic)_glowImage).color = cGlowIdle; _glowImage.type = (Type)1; _glowImage.preserveAspect = false; _glowRect = val5.GetComponent(); _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(val6); _fillImage.sprite = sprite4; ((Graphic)_fillImage).color = cGreen; _fillImage.type = (Type)1; _fillImage.preserveAspect = false; _fillRect = val6.GetComponent(); _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(val7); _label.font = Resources.GetBuiltinResource("Arial.ttf"); _label.fontSize = 7; _label.alignment = (TextAnchor)4; ((Graphic)_label).color = Color.white; _label.text = ""; _label.horizontalOverflow = (HorizontalWrapMode)1; RectTransform component4 = val7.GetComponent(); 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()) == 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()); 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 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()); 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()); 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()); 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(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()); 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()) == 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", }; } } }