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