Decompiled source of VoiceFix v1.0.1

VoiceFixMod.dll

Decompiled 6 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyCompany("VoiceFixMod")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("My first plugin")]
[assembly: AssemblyTitle("VoiceFixMod")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 VoiceFixMod
{
	[BepInPlugin("com.Kingo.voicefix", "VoiceFixMod", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string GUID = "com.Kingo.voicefix";

		public const string Name = "VoiceFixMod";

		public const string Version = "1.0.0";

		internal static ManualLogSource LogS;

		private Harmony _harmony;

		private static ConfigEntry<float> _silenceSecondsBeforeReinit;

		private static ConfigEntry<float> _keepAliveEverySeconds;

		private static ConfigEntry<float> _reinitCooldownSeconds;

		private static ConfigEntry<bool> _enableAutoReinit;

		private static ConfigEntry<bool> _enableKeepAlive;

		private static ConfigEntry<bool> _verboseLogs;

		private static ConfigEntry<KeyCode> _forceReinitKey;

		private VoiceFixController _controller;

		private GameObject _controllerGO;

		private void Awake()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Expected O, but got Unknown
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			LogS = ((BaseUnityPlugin)this).Logger;
			_harmony = new Harmony("com.Kingo.voicefix");
			_harmony.PatchAll();
			_silenceSecondsBeforeReinit = ((BaseUnityPlugin)this).Config.Bind<float>("Watchdog", "SilenceSecondsBeforeReinit", 35f, "If no inbound voice is heard for this many seconds, re-initialize voice.");
			_keepAliveEverySeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Watchdog", "KeepAliveEverySeconds", 8f, "How often to send a tiny keep-alive (quick mic toggle) to prevent idle timeouts.");
			_reinitCooldownSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Watchdog", "ReinitCooldownSeconds", 20f, "Minimum time between automatic re-inits.");
			_enableAutoReinit = ((BaseUnityPlugin)this).Config.Bind<bool>("Watchdog", "EnableAutoReinit", true, "Automatically re-initialize voice when silence threshold is reached.");
			_enableKeepAlive = ((BaseUnityPlugin)this).Config.Bind<bool>("Watchdog", "EnableKeepAlive", true, "Periodically nudge the voice backend so it doesn't sleep.");
			_verboseLogs = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "VerboseLogs", false, "Extra debug logs.");
			_forceReinitKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Hotkeys", "ForceReinitKey", (KeyCode)291, "Hold LeftShift + press this key to force a voice re-init.");
			_controllerGO = new GameObject("VoiceFixMod_Controller");
			_controller = _controllerGO.AddComponent<VoiceFixController>();
			_controller.Init(_silenceSecondsBeforeReinit.Value, _keepAliveEverySeconds.Value, _reinitCooldownSeconds.Value, _enableAutoReinit.Value, _enableKeepAlive.Value, _verboseLogs.Value, _forceReinitKey.Value);
			Object.DontDestroyOnLoad((Object)(object)_controllerGO);
			LogS.LogInfo((object)("VoiceFixMod 1.0.0 loaded. GameRoot: " + Paths.GameRootPath));
		}

		private void OnDestroy()
		{
			try
			{
				Harmony harmony = _harmony;
				if (harmony != null)
				{
					harmony.UnpatchSelf();
				}
			}
			catch
			{
			}
			if (!((Object)(object)_controller != (Object)null))
			{
				return;
			}
			try
			{
				Object.Destroy((Object)(object)_controller);
			}
			catch
			{
			}
			try
			{
				if (Object.op_Implicit((Object)(object)_controllerGO))
				{
					Object.Destroy((Object)(object)_controllerGO);
				}
			}
			catch
			{
			}
		}
	}
	internal class VoiceFixController : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <LateStart>d__18 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public VoiceFixController <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <LateStart>d__18(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(2f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					<>4__this.DiscoverBackend();
					<>4__this.AttachAudioTaps();
					<>4__this._inited = true;
					Plugin.LogS.LogInfo((object)"[VoiceFix] Initialization complete.");
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <ReinitializeVoice>d__25 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public string reason;

			public VoiceFixController <>4__this;

			private Behaviour[] <comps>5__1;

			private Behaviour[] <>s__2;

			private int <>s__3;

			private Behaviour <comp>5__4;

			private Type <t>5__5;

			private bool <invokedAny>5__6;

			private bool <needDelay>5__7;

			private string[] <tries>5__8;

			private string[] <>s__9;

			private int <>s__10;

			private string <name>5__11;

			private MethodInfo <m>5__12;

			private Exception <ex>5__13;

			private Exception <ex>5__14;

			private bool <disabled>5__15;

			private Exception <ex>5__16;

			private Exception <ex>5__17;

			private int <i>5__18;

			private AudioActivityTap <tap>5__19;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <ReinitializeVoice>d__25(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<comps>5__1 = null;
				<>s__2 = null;
				<comp>5__4 = null;
				<t>5__5 = null;
				<tries>5__8 = null;
				<>s__9 = null;
				<name>5__11 = null;
				<m>5__12 = null;
				<ex>5__13 = null;
				<ex>5__14 = null;
				<ex>5__16 = null;
				<ex>5__17 = null;
				<tap>5__19 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0358: Unknown result type (might be due to invalid IL or missing references)
				//IL_0362: Expected O, but got Unknown
				//IL_03e5: Unknown result type (might be due to invalid IL or missing references)
				//IL_03ef: Expected O, but got Unknown
				//IL_0509: Unknown result type (might be due to invalid IL or missing references)
				//IL_0513: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>4__this._lastReinit = Time.realtimeSinceStartup;
					Plugin.LogS.LogWarning((object)("[VoiceFix] Re-initializing voice (" + reason + ")."));
					<comps>5__1 = (Behaviour[])(object)new Behaviour[3] { <>4__this._dissonanceComms, <>4__this._vivoxMgr, <>4__this._genericVoiceMgr };
					<>s__2 = <comps>5__1;
					<>s__3 = 0;
					goto IL_045d;
				case 1:
					<>1__state = -1;
					goto IL_0372;
				case 2:
					<>1__state = -1;
					try
					{
						<comp>5__4.enabled = true;
					}
					catch (Exception ex)
					{
						<ex>5__17 = ex;
						Plugin.LogS.LogWarning((object)("[VoiceFix] Soft-enable failed: " + <ex>5__17.Message));
					}
					goto IL_0440;
				case 3:
					{
						<>1__state = -1;
						<>4__this.AttachAudioTaps();
						<>4__this._lastHeardTime = Time.realtimeSinceStartup;
						Plugin.LogS.LogInfo((object)"[VoiceFix] Voice re-init attempt complete.");
						return false;
					}
					IL_045d:
					if (<>s__3 < <>s__2.Length)
					{
						<comp>5__4 = <>s__2[<>s__3];
						if ((Object)(object)<comp>5__4 == (Object)null)
						{
							goto IL_044f;
						}
						<t>5__5 = ((object)<comp>5__4).GetType();
						<invokedAny>5__6 = false;
						<needDelay>5__7 = false;
						try
						{
							<tries>5__8 = new string[10] { "Reset", "Reinit", "ReInitialize", "Initialize", "Init", "Shutdown", "Stop", "Start", "Login", "Reconnect" };
							<>s__9 = <tries>5__8;
							for (<>s__10 = 0; <>s__10 < <>s__9.Length; <>s__10++)
							{
								<name>5__11 = <>s__9[<>s__10];
								<m>5__12 = <t>5__5.GetMethod(<name>5__11, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
								if ((object)<m>5__12 != null)
								{
									if (<>4__this._verbose)
									{
										Plugin.LogS.LogDebug((object)("[VoiceFix] Calling " + <t>5__5.Name + "." + <name>5__11 + "()"));
									}
									try
									{
										<m>5__12.Invoke(<comp>5__4, null);
										<invokedAny>5__6 = true;
										if (<name>5__11.Equals("Shutdown", StringComparison.OrdinalIgnoreCase) || <name>5__11.Equals("Stop", StringComparison.OrdinalIgnoreCase))
										{
											<needDelay>5__7 = true;
										}
									}
									catch (Exception ex)
									{
										<ex>5__13 = ex;
										Plugin.LogS.LogWarning((object)("[VoiceFix] " + <t>5__5.Name + "." + <name>5__11 + "() invocation failed: " + <ex>5__13.Message));
									}
								}
								<m>5__12 = null;
								<name>5__11 = null;
							}
							<>s__9 = null;
							<tries>5__8 = null;
						}
						catch (Exception ex)
						{
							<ex>5__14 = ex;
							Plugin.LogS.LogWarning((object)("[VoiceFix] Reinit reflection on " + <t>5__5.FullName + " failed: " + <ex>5__14.Message));
						}
						if (<needDelay>5__7)
						{
							<>2__current = (object)new WaitForSeconds(0.15f);
							<>1__state = 1;
							return true;
						}
						goto IL_0372;
					}
					<>s__2 = null;
					<i>5__18 = 0;
					while (<i>5__18 < <>4__this._taps.Count)
					{
						<tap>5__19 = <>4__this._taps[<i>5__18];
						if (Object.op_Implicit((Object)(object)<tap>5__19))
						{
							Object.Destroy((Object)(object)<tap>5__19);
						}
						<tap>5__19 = null;
						<i>5__18++;
					}
					<>4__this._taps.Clear();
					<>2__current = (object)new WaitForSeconds(0.25f);
					<>1__state = 3;
					return true;
					IL_0440:
					<t>5__5 = null;
					<comp>5__4 = null;
					goto IL_044f;
					IL_0372:
					if (!<invokedAny>5__6)
					{
						<disabled>5__15 = false;
						try
						{
							<comp>5__4.enabled = false;
							<disabled>5__15 = true;
						}
						catch (Exception ex)
						{
							<ex>5__16 = ex;
							Plugin.LogS.LogWarning((object)("[VoiceFix] Soft-disable failed: " + <ex>5__16.Message));
						}
						if (<disabled>5__15)
						{
							<>2__current = (object)new WaitForSeconds(0.05f);
							<>1__state = 2;
							return true;
						}
					}
					goto IL_0440;
					IL_044f:
					<>s__3++;
					goto IL_045d;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <SendKeepAlive>d__24 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public VoiceFixController <>4__this;

			private bool <nudged>5__1;

			private Type <t>5__2;

			private PropertyInfo <prop>5__3;

			private object <currObj>5__4;

			private bool <curr>5__5;

			private bool <setOk>5__6;

			private Exception <ex>5__7;

			private Exception <ex>5__8;

			private Exception <ex>5__9;

			private bool <disabled>5__10;

			private Exception <ex>5__11;

			private Exception <ex>5__12;

			private bool <disabled>5__13;

			private Exception <ex>5__14;

			private Exception <ex>5__15;

			private bool <disabled>5__16;

			private Exception <ex>5__17;

			private Exception <ex>5__18;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <SendKeepAlive>d__24(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<t>5__2 = null;
				<prop>5__3 = null;
				<currObj>5__4 = null;
				<ex>5__7 = null;
				<ex>5__8 = null;
				<ex>5__9 = null;
				<ex>5__11 = null;
				<ex>5__12 = null;
				<ex>5__14 = null;
				<ex>5__15 = null;
				<ex>5__17 = null;
				<ex>5__18 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					if (<>4__this._verbose)
					{
						Plugin.LogS.LogDebug((object)"[VoiceFix] Keep-alive tick.");
					}
					<nudged>5__1 = false;
					if ((Object)(object)<>4__this._dissonanceComms != (Object)null)
					{
						<t>5__2 = ((object)<>4__this._dissonanceComms).GetType();
						<prop>5__3 = <>4__this.FindFirstProperty(<t>5__2, new string[5] { "IsMuted", "IsMicMuted", "Muted", "isMuted", "muted" });
						if ((object)<prop>5__3 != null)
						{
							<currObj>5__4 = null;
							try
							{
								<currObj>5__4 = <prop>5__3.GetValue(<>4__this._dissonanceComms, null);
							}
							catch (Exception ex)
							{
								<ex>5__7 = ex;
								Plugin.LogS.LogDebug((object)("[VoiceFix] prop.GetValue failed: " + <ex>5__7.Message));
							}
							<curr>5__5 = <>4__this.SafeConvertToBool(<currObj>5__4, fallback: false);
							<setOk>5__6 = false;
							try
							{
								<prop>5__3.SetValue(<>4__this._dissonanceComms, !<curr>5__5, null);
								<setOk>5__6 = true;
							}
							catch (Exception ex)
							{
								<ex>5__8 = ex;
								Plugin.LogS.LogDebug((object)("[VoiceFix] prop.SetValue failed (set): " + <ex>5__8.Message));
							}
							if (<setOk>5__6)
							{
								<>2__current = null;
								<>1__state = 1;
								return true;
							}
							goto IL_0243;
						}
						<disabled>5__10 = false;
						try
						{
							<>4__this._dissonanceComms.enabled = false;
							<disabled>5__10 = true;
						}
						catch (Exception ex)
						{
							<ex>5__11 = ex;
							Plugin.LogS.LogDebug((object)("[VoiceFix] Dissonance disable failed: " + <ex>5__11.Message));
						}
						if (<disabled>5__10)
						{
							<>2__current = null;
							<>1__state = 2;
							return true;
						}
						goto IL_0314;
					}
					if ((Object)(object)<>4__this._vivoxMgr != (Object)null)
					{
						<disabled>5__13 = false;
						try
						{
							<>4__this._vivoxMgr.enabled = false;
							<disabled>5__13 = true;
						}
						catch (Exception ex)
						{
							<ex>5__14 = ex;
							Plugin.LogS.LogDebug((object)("[VoiceFix] Vivox disable failed: " + <ex>5__14.Message));
						}
						if (<disabled>5__13)
						{
							<>2__current = null;
							<>1__state = 3;
							return true;
						}
					}
					else if ((Object)(object)<>4__this._genericVoiceMgr != (Object)null)
					{
						<disabled>5__16 = false;
						try
						{
							<>4__this._genericVoiceMgr.enabled = false;
							<disabled>5__16 = true;
						}
						catch (Exception ex)
						{
							<ex>5__17 = ex;
							Plugin.LogS.LogDebug((object)("[VoiceFix] Generic disable failed: " + <ex>5__17.Message));
						}
						if (<disabled>5__16)
						{
							<>2__current = null;
							<>1__state = 4;
							return true;
						}
					}
					break;
				case 1:
					<>1__state = -1;
					try
					{
						<prop>5__3.SetValue(<>4__this._dissonanceComms, <curr>5__5, null);
						<nudged>5__1 = true;
					}
					catch (Exception ex)
					{
						<ex>5__9 = ex;
						Plugin.LogS.LogDebug((object)("[VoiceFix] prop.SetValue failed (restore): " + <ex>5__9.Message));
					}
					goto IL_0243;
				case 2:
					<>1__state = -1;
					try
					{
						<>4__this._dissonanceComms.enabled = true;
						<nudged>5__1 = true;
					}
					catch (Exception ex)
					{
						<ex>5__12 = ex;
						Plugin.LogS.LogDebug((object)("[VoiceFix] Dissonance enable failed: " + <ex>5__12.Message));
					}
					goto IL_0314;
				case 3:
					<>1__state = -1;
					try
					{
						<>4__this._vivoxMgr.enabled = true;
						<nudged>5__1 = true;
					}
					catch (Exception ex)
					{
						<ex>5__15 = ex;
						Plugin.LogS.LogDebug((object)("[VoiceFix] Vivox enable failed: " + <ex>5__15.Message));
					}
					break;
				case 4:
					{
						<>1__state = -1;
						try
						{
							<>4__this._genericVoiceMgr.enabled = true;
							<nudged>5__1 = true;
						}
						catch (Exception ex)
						{
							<ex>5__18 = ex;
							Plugin.LogS.LogDebug((object)("[VoiceFix] Generic enable failed: " + <ex>5__18.Message));
						}
						break;
					}
					IL_0314:
					<t>5__2 = null;
					<prop>5__3 = null;
					break;
					IL_0243:
					<currObj>5__4 = null;
					goto IL_0314;
				}
				if (<>4__this._verbose)
				{
					Plugin.LogS.LogDebug((object)(<nudged>5__1 ? "[VoiceFix] Keep-alive nudge sent." : "[VoiceFix] Keep-alive skipped (no backend)."));
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private float _silenceSecondsBeforeReinit;

		private float _keepAliveEverySeconds;

		private float _reinitCooldownSeconds;

		private bool _enableAutoReinit;

		private bool _enableKeepAlive;

		private bool _verbose;

		private KeyCode _forceKey;

		private float _lastHeardTime;

		private float _lastKeepAlive;

		private float _lastReinit;

		private bool _inited;

		private Behaviour _dissonanceComms;

		private Behaviour _vivoxMgr;

		private Behaviour _genericVoiceMgr;

		private readonly List<AudioActivityTap> _taps = new List<AudioActivityTap>();

		private const float DiscoveryInterval = 12f;

		private float _lastDiscovery;

		public void Init(float silence, float keepalive, float cooldown, bool autoReinit, bool keepAlive, bool verbose, KeyCode forceKey)
		{
			//IL_004d: 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)
			_silenceSecondsBeforeReinit = Mathf.Max(5f, silence);
			_keepAliveEverySeconds = Mathf.Max(5f, keepalive);
			_reinitCooldownSeconds = Mathf.Max(5f, cooldown);
			_enableAutoReinit = autoReinit;
			_enableKeepAlive = keepAlive;
			_verbose = verbose;
			_forceKey = forceKey;
			_lastHeardTime = Time.realtimeSinceStartup;
			_lastKeepAlive = 0f;
			_lastReinit = -999f;
			_lastDiscovery = -999f;
			((MonoBehaviour)this).StartCoroutine(LateStart());
		}

		private IEnumerator LateStart()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LateStart>d__18(0)
			{
				<>4__this = this
			};
		}

		private void Update()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (!_inited)
			{
				return;
			}
			if (Input.GetKey((KeyCode)304) && Input.GetKeyDown(_forceKey))
			{
				Plugin.LogS.LogWarning((object)"[VoiceFix] Manual re-init requested.");
				((MonoBehaviour)this).StartCoroutine(ReinitializeVoice("manual-hotkey"));
			}
			bool flag = false;
			for (int i = 0; i < _taps.Count; i++)
			{
				AudioActivityTap audioActivityTap = _taps[i];
				if (!((Object)(object)audioActivityTap == (Object)null) && audioActivityTap.ConsumeActivity())
				{
					flag = true;
					break;
				}
			}
			if (flag)
			{
				HeardActivity();
			}
			if (_enableKeepAlive && Time.realtimeSinceStartup - _lastKeepAlive >= _keepAliveEverySeconds)
			{
				_lastKeepAlive = Time.realtimeSinceStartup;
				((MonoBehaviour)this).StartCoroutine(SendKeepAlive());
			}
			if (_enableAutoReinit && Time.realtimeSinceStartup - _lastHeardTime >= _silenceSecondsBeforeReinit && Time.realtimeSinceStartup - _lastReinit >= _reinitCooldownSeconds)
			{
				Plugin.LogS.LogWarning((object)"[VoiceFix] No inbound voice detected for threshold; attempting re-init.");
				((MonoBehaviour)this).StartCoroutine(ReinitializeVoice("silence-watchdog"));
			}
			if (Time.realtimeSinceStartup - _lastDiscovery >= 12f)
			{
				_lastDiscovery = Time.realtimeSinceStartup;
				DiscoverBackend();
			}
		}

		private void DiscoverBackend()
		{
			try
			{
				_dissonanceComms = null;
				_vivoxMgr = null;
				_genericVoiceMgr = null;
				_dissonanceComms = FindBehaviourByTypeName("DissonanceComms");
				if ((Object)(object)_dissonanceComms != (Object)null)
				{
					Plugin.LogS.LogInfo((object)"[VoiceFix] Found DissonanceComms.");
				}
				_vivoxMgr = FindBehaviourByTypeName("VivoxVoiceManager");
				if ((Object)(object)_vivoxMgr != (Object)null)
				{
					Plugin.LogS.LogInfo((object)"[VoiceFix] Found VivoxVoiceManager.");
				}
				if ((Object)(object)_dissonanceComms == (Object)null && (Object)(object)_vivoxMgr == (Object)null)
				{
					Behaviour genericVoiceMgr = ((IEnumerable<Behaviour>)Object.FindObjectsOfType<Behaviour>()).FirstOrDefault((Func<Behaviour, bool>)((Behaviour c) => (Object)(object)c != (Object)null && ((object)c).GetType().Name.IndexOf("Voice", StringComparison.OrdinalIgnoreCase) >= 0 && ((object)c).GetType().Name.IndexOf("Manager", StringComparison.OrdinalIgnoreCase) >= 0));
					_genericVoiceMgr = genericVoiceMgr;
					if ((Object)(object)_genericVoiceMgr != (Object)null)
					{
						Plugin.LogS.LogInfo((object)("[VoiceFix] Found generic voice manager: " + ((object)_genericVoiceMgr).GetType().FullName));
					}
					else
					{
						Plugin.LogS.LogWarning((object)"[VoiceFix] No obvious voice backend found; watchdog will still monitor audio sources.");
					}
				}
			}
			catch (Exception arg)
			{
				Plugin.LogS.LogError((object)$"[VoiceFix] Discovery error: {arg}");
			}
		}

		private Behaviour FindBehaviourByTypeName(string typeName)
		{
			Behaviour[] array = Object.FindObjectsOfType<Behaviour>();
			foreach (Behaviour val in array)
			{
				if (!((Object)(object)val == (Object)null))
				{
					Type type = ((object)val).GetType();
					if (type.Name.Equals(typeName, StringComparison.OrdinalIgnoreCase) || (type.FullName != null && type.FullName.EndsWith("." + typeName, StringComparison.OrdinalIgnoreCase)))
					{
						return val;
					}
				}
			}
			return null;
		}

		private void AttachAudioTaps()
		{
			List<GameObject> list = new List<GameObject>();
			try
			{
				GameObject[] array = GameObject.FindGameObjectsWithTag("Player");
				if (array != null && array.Length != 0)
				{
					list.AddRange(array);
				}
			}
			catch
			{
			}
			AudioSource[] array2 = Object.FindObjectsOfType<AudioSource>();
			foreach (AudioSource val in array2)
			{
				if (!((Object)(object)val == (Object)null) && ((Behaviour)val).enabled && ((Component)val).gameObject.activeInHierarchy)
				{
					string text = ((Object)((Component)val).gameObject).name.ToLowerInvariant();
					if (text.Contains("voice") || text.Contains("dissonance") || text.Contains("vivox") || text.Contains("radio") || text.Contains("prox"))
					{
						list.Add(((Component)val).gameObject);
					}
					else if ((Object)(object)val.clip == (Object)null)
					{
						list.Add(((Component)val).gameObject);
					}
				}
			}
			list = list.Distinct().ToList();
			int num = 0;
			foreach (GameObject item in list)
			{
				if (!((Object)(object)item == (Object)null))
				{
					AudioActivityTap audioActivityTap = item.GetComponent<AudioActivityTap>();
					if ((Object)(object)audioActivityTap == (Object)null)
					{
						audioActivityTap = item.AddComponent<AudioActivityTap>();
					}
					if (!_taps.Contains(audioActivityTap))
					{
						_taps.Add(audioActivityTap);
					}
					num++;
				}
			}
			Plugin.LogS.LogInfo((object)$"[VoiceFix] Attached audio activity taps to {num} object(s).");
		}

		private void HeardActivity()
		{
			_lastHeardTime = Time.realtimeSinceStartup;
			if (_verbose)
			{
				Plugin.LogS.LogDebug((object)$"[VoiceFix] Heard inbound audio @ {_lastHeardTime:F1}s");
			}
		}

		private IEnumerator SendKeepAlive()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <SendKeepAlive>d__24(0)
			{
				<>4__this = this
			};
		}

		private IEnumerator ReinitializeVoice(string reason)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ReinitializeVoice>d__25(0)
			{
				<>4__this = this,
				reason = reason
			};
		}

		private PropertyInfo FindFirstProperty(Type t, string[] candidates)
		{
			foreach (string name in candidates)
			{
				PropertyInfo property = t.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if ((object)property != null)
				{
					return property;
				}
			}
			return null;
		}

		private bool SafeConvertToBool(object o, bool fallback)
		{
			if (o == null)
			{
				return fallback;
			}
			try
			{
				return Convert.ToBoolean(o);
			}
			catch
			{
				return fallback;
			}
		}
	}
	internal class AudioActivityTap : MonoBehaviour
	{
		private const float Threshold = 0.0005f;

		private volatile int _activityFlag = 0;

		private void OnAudioFilterRead(float[] data, int channels)
		{
			if (data != null && data.Length != 0)
			{
				int num = Math.Max(1, channels);
				double num2 = 0.0;
				for (int i = 0; i < data.Length; i += num)
				{
					num2 += (double)Math.Abs(data[i]);
				}
				double num3 = Math.Max(1, data.Length / num);
				double num4 = num2 / num3;
				if (num4 > 0.0005000000237487257)
				{
					Interlocked.Exchange(ref _activityFlag, 1);
				}
			}
		}

		public bool ConsumeActivity()
		{
			int num = Interlocked.Exchange(ref _activityFlag, 0);
			return num != 0;
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "VoiceFixMod";

		public const string PLUGIN_NAME = "My first plugin";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}