Decompiled source of ProximityVoiceChat v1.0.2

ProximityVoiceChat.dll

Decompiled 9 hours ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Concentus.Celt;
using Concentus.Celt.Structs;
using Concentus.Common;
using Concentus.Common.CPlusPlus;
using Concentus.Enums;
using Concentus.Silk;
using Concentus.Silk.Enums;
using Concentus.Silk.Structs;
using Concentus.Structs;
using HarmonyLib;
using JetBrains.Annotations;
using LocalizationManager;
using Microsoft.CodeAnalysis;
using ProximityVoiceChat.UI;
using ProximityVoiceChat.Voice;
using ProximityVoiceChat.Voice.Audio;
using ServerSync;
using Splatform;
using Steamworks;
using TMPro;
using UIManager;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.U2D;
using UnityEngine.UI;
using UserManagement;
using Valheim.SettingsGui;
using Valheim.UI;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Core.ObjectPool;
using YamlDotNet.Core.Tokens;
using YamlDotNet.Helpers;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.BufferedDeserialization;
using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators;
using YamlDotNet.Serialization.Callbacks;
using YamlDotNet.Serialization.Converters;
using YamlDotNet.Serialization.EventEmitters;
using YamlDotNet.Serialization.NamingConventions;
using YamlDotNet.Serialization.NodeDeserializers;
using YamlDotNet.Serialization.NodeTypeResolvers;
using YamlDotNet.Serialization.ObjectFactories;
using YamlDotNet.Serialization.ObjectGraphTraversalStrategies;
using YamlDotNet.Serialization.ObjectGraphVisitors;
using YamlDotNet.Serialization.Schemas;
using YamlDotNet.Serialization.TypeInspectors;
using YamlDotNet.Serialization.TypeResolvers;
using YamlDotNet.Serialization.Utilities;
using YamlDotNet.Serialization.ValueDeserializers;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ProximityVoiceChat")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Azumatt")]
[assembly: AssemblyProduct("ProximityVoiceChat")]
[assembly: AssemblyCopyright("Copyright ©  2022")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("E0E2F92E-557C-4A05-9D89-AA92A0BD75C4")]
[assembly: AssemblyFileVersion("1.0.2")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.2.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class ExtensionMarkerAttribute : Attribute
	{
		public ExtensionMarkerAttribute(string name)
		{
		}
	}
}
namespace ProximityVoiceChat
{
	[BepInPlugin("Azumatt.ProximityVoiceChat", "ProximityVoiceChat", "1.0.2")]
	public class ProximityVoiceChatPlugin : BaseUnityPlugin
	{
		public enum Toggle
		{
			On = 1,
			Off = 0
		}

		public enum Bone
		{
			X,
			Y,
			Z
		}

		private class AcceptableShortcuts : AcceptableValueBase
		{
			public AcceptableShortcuts()
				: base(typeof(KeyboardShortcut))
			{
			}

			public override object Clamp(object value)
			{
				return value;
			}

			public override bool IsValid(object value)
			{
				return true;
			}

			public override string ToDescriptionString()
			{
				return "# Acceptable values: " + string.Join(", ", UnityInput.Current.SupportedKeyCodes);
			}
		}

		private class ConfigurationManagerAttributes
		{
			[UsedImplicitly]
			public int? Order;

			[UsedImplicitly]
			public bool? Browsable;

			[UsedImplicitly]
			public string? Category;

			[UsedImplicitly]
			public Action<ConfigEntryBase>? CustomDrawer;
		}

		internal const string ModName = "ProximityVoiceChat";

		internal const string ModVersion = "1.0.2";

		internal const string Author = "Azumatt";

		private const string ModGUID = "Azumatt.ProximityVoiceChat";

		private static readonly string ConfigFileName = "Azumatt.ProximityVoiceChat.cfg";

		private static readonly string ConfigFileFullPath = Paths.ConfigPath + Path.DirectorySeparatorChar + ConfigFileName;

		private readonly Harmony _harmony = new Harmony("Azumatt.ProximityVoiceChat");

		private static GameObject _runtimeObject = null;

		internal static ProximityVoiceChatPlugin? Instance;

		public static readonly ManualLogSource Log = Logger.CreateLogSource("ProximityVoiceChat");

		private static readonly ConfigSync ConfigSync = new ConfigSync("Azumatt.ProximityVoiceChat")
		{
			DisplayName = "ProximityVoiceChat",
			CurrentVersion = "1.0.2",
			MinimumRequiredVersion = "1.0.2",
			IsLocked = false
		};

		private static ConfigEntry<Toggle> _serverConfigLocked = null;

		internal static ConfigEntry<float> MaxRange = null;

		internal static ConfigEntry<float> RangeHysteresis = null;

		internal static ConfigEntry<float> FullVolumeRange = null;

		internal static ConfigEntry<Toggle> EnableVoice = null;

		internal static ConfigEntry<string> InputDevice = null;

		internal static ConfigEntry<Toggle> MuteSelf = null;

		internal static ConfigEntry<KeyboardShortcut> MuteSelfKey = null;

		internal static ConfigEntry<Toggle> UseVoiceActivation = null;

		internal static ConfigEntry<KeyboardShortcut> PushToTalkKey = null;

		internal static ConfigEntry<float> ActivationThreshold = null;

		internal static ConfigEntry<float> MicGain = null;

		internal static ConfigEntry<Toggle> AutoGain = null;

		internal static ConfigEntry<float> AutoGainTarget = null;

		internal static ConfigEntry<int> Bitrate = null;

		internal static ConfigEntry<int> ExpectedPacketLoss = null;

		internal static ConfigEntry<Toggle> UseDtx = null;

		internal static ConfigEntry<Toggle> AdaptiveFec = null;

		internal static ConfigEntry<float> VoiceVolume = null;

		internal static ConfigEntry<Toggle> Deafen = null;

		internal static ConfigEntry<KeyboardShortcut> DeafenKey = null;

		internal static ConfigEntry<float> MonitorVolume = null;

		internal static ConfigEntry<int> JitterTargetMs = null;

		internal static ConfigEntry<int> JitterMaxMs = null;

		internal static ConfigEntry<Toggle> AdaptiveJitter = null;

		internal static ConfigEntry<Toggle> DuckMusic = null;

		internal static ConfigEntry<float> DuckMusicAmount = null;

		internal static ConfigEntry<Toggle> Occlusion = null;

		internal static ConfigEntry<float> OccludedCutoff = null;

		internal static ConfigEntry<float> OccludedVolume = null;

		internal static ConfigEntry<Toggle> UnderwaterMuffle = null;

		internal static ConfigEntry<float> UnderwaterCutoff = null;

		internal static ConfigEntry<Toggle> VoiceReverb = null;

		internal static ConfigEntry<float> ReverbMix = null;

		internal static ConfigEntry<Toggle> ShowSpeakingIndicator = null;

		internal static ConfigEntry<float> SpeakingIndicatorHeight = null;

		internal static ConfigEntry<Toggle> PeerIndicators = null;

		internal static ConfigEntry<float> PeerIndicatorHeight = null;

		internal static ConfigEntry<float> PeerIndicatorScale = null;

		internal static ConfigEntry<Toggle> PeerIndicatorThroughWalls = null;

		internal static ConfigEntry<Toggle> JawMovement = null;

		internal static ConfigEntry<float> JawMaxAngle = null;

		internal static ConfigEntry<float> JawSensitivity = null;

		internal static ConfigEntry<Bone> JawAxis = null;

		internal static ConfigEntry<Toggle> HotkeyMessages = null;

		internal static ConfigEntry<Toggle> TestTone = null;

		internal static ConfigEntry<Toggle> LoopbackTest = null;

		internal static ConfigEntry<string> PerPlayerSettings = null;

		public void Awake()
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Expected O, but got Unknown
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Expected O, but got Unknown
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Expected O, but got Unknown
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Expected O, but got Unknown
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Expected O, but got Unknown
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Expected O, but got Unknown
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Expected O, but got Unknown
			//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d4: Expected O, but got Unknown
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0302: Expected O, but got Unknown
			//IL_0368: Unknown result type (might be due to invalid IL or missing references)
			//IL_0373: Expected O, but got Unknown
			//IL_03a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c4: Expected O, but got Unknown
			//IL_03f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fd: Expected O, but got Unknown
			//IL_0425: Unknown result type (might be due to invalid IL or missing references)
			//IL_0430: Expected O, but got Unknown
			//IL_045b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0466: Expected O, but got Unknown
			//IL_04cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d7: Expected O, but got Unknown
			//IL_0521: Unknown result type (might be due to invalid IL or missing references)
			//IL_052c: Expected O, but got Unknown
			//IL_055a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0565: Expected O, but got Unknown
			//IL_05af: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ba: Expected O, but got Unknown
			//IL_0604: Unknown result type (might be due to invalid IL or missing references)
			//IL_060f: Expected O, but got Unknown
			//IL_0659: Unknown result type (might be due to invalid IL or missing references)
			//IL_0664: Expected O, but got Unknown
			//IL_06ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_06b9: Expected O, but got Unknown
			//IL_06e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_06f2: Expected O, but got Unknown
			//IL_0758: Unknown result type (might be due to invalid IL or missing references)
			//IL_0763: Expected O, but got Unknown
			//IL_0791: Unknown result type (might be due to invalid IL or missing references)
			//IL_079c: Expected O, but got Unknown
			//IL_0841: Unknown result type (might be due to invalid IL or missing references)
			//IL_084c: Expected O, but got Unknown
			//IL_088b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0895: Expected O, but got Unknown
			Instance = this;
			Localizer.Load();
			bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet;
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
			_serverConfigLocked = config("1 - General", "Lock Configuration", Toggle.On, "If on, only server admins can change the synced settings.");
			ConfigSync.AddLockingConfigEntry<Toggle>(_serverConfigLocked);
			MaxRange = config("2 - Proximity", "Max Range", 45f, new ConfigDescription("Max distance you can hear other players", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 200f), Array.Empty<object>()));
			RangeHysteresis = config("2 - Proximity", "Range Buffer", 8f, new ConfigDescription("Extra distance before a player disconnects from voice. Helps prevent audio cutting in and out near max range.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), Array.Empty<object>()));
			FullVolumeRange = config("2 - Proximity", "Full Volume Range", 4f, new ConfigDescription("Players within this distance are heard at full volume. Beyond it, volume fades with distance.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 40f), Array.Empty<object>()));
			EnableVoice = config("3 - Microphone", "Enable Voice", Toggle.On, "Turn microphone capture off entirely.", synchronizedSetting: false);
			InputDevice = config("3 - Microphone", "Input Device", "", "Microphone to use. Leave blank to use your system default.", synchronizedSetting: false);
			MuteSelf = config("3 - Microphone", "Mute Self", Toggle.Off, "Stops sending your voice without turning off the microphone.", synchronizedSetting: false);
			MuteSelfKey = config<KeyboardShortcut>("3 - Microphone", "Mute Self Key", new KeyboardShortcut((KeyCode)0, Array.Empty<KeyCode>()), new ConfigDescription("Toggles your microphone mute. Unbound by default to avoid conflicts with other mods.", (AcceptableValueBase)(object)new AcceptableShortcuts(), Array.Empty<object>()), synchronizedSetting: false);
			UseVoiceActivation = config("3 - Microphone", "Use Voice Activation", Toggle.Off, "Automatically transmits when you speak. Turn this off to use push-to-talk.", synchronizedSetting: false);
			PushToTalkKey = config<KeyboardShortcut>("3 - Microphone", "Push To Talk", new KeyboardShortcut((KeyCode)98, Array.Empty<KeyCode>()), new ConfigDescription("Hold this key to talk when Voice Activation is off.", (AcceptableValueBase)(object)new AcceptableShortcuts(), Array.Empty<object>()), synchronizedSetting: false);
			ActivationThreshold = config("3 - Microphone", "Activation Threshold", 0.02f, new ConfigDescription("How loud you need to speak before voice activation starts transmitting. Lower values are more sensitive.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.001f, 0.3f), Array.Empty<object>()), synchronizedSetting: false);
			MicGain = config("3 - Microphone", "Microphone Gain", 1f, new ConfigDescription("Boosts or lowers your microphone volume before it is sent. Checked before encoding", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 8f), Array.Empty<object>()), synchronizedSetting: false);
			AutoGain = config("3 - Microphone", "Auto Gain", Toggle.On, "Chases a steady speaking level so you do not have to hunt for a gain number. Microphone Gain still multiplies on top.", synchronizedSetting: false);
			AutoGainTarget = config("3 - Microphone", "Auto Gain Target", 0.12f, new ConfigDescription("Target speaking volume used by Automatic Gain. Higher values make your voice louder.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.02f, 0.4f), Array.Empty<object>()), synchronizedSetting: false);
			Bitrate = config("4 - Codec", "Bitrate", 24000, new ConfigDescription("Opus target bitrate in bits per second. Voice quality and bandwidth usage. Higher is better but uses more bandwidth.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(6000, 64000), Array.Empty<object>()));
			ExpectedPacketLoss = config("4 - Codec", "Expected Packet Loss", 5, new ConfigDescription("How much packet loss Opus should expect. Higher values use more error correction.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 40), Array.Empty<object>()));
			UseDtx = config("4 - Codec", "Use DTX", Toggle.Off, "Stops sending audio while you are silent. Saves bandwidth, but very quiet words may get cut off.");
			AdaptiveFec = config("4 - Codec", "Adaptive FEC", Toggle.On, "Adds more error correction when other players report lost audio packets.", synchronizedSetting: false);
			VoiceVolume = config("5 - Playback", "Voice Volume", 1f, new ConfigDescription("Overall volume of voice chat.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), Array.Empty<object>()), synchronizedSetting: false);
			Deafen = config("5 - Playback", "Deafen", Toggle.Off, "Stops all incoming voice and stops you transmitting.", synchronizedSetting: false);
			DeafenKey = config<KeyboardShortcut>("5 - Playback", "Deafen Key", new KeyboardShortcut((KeyCode)0, Array.Empty<KeyCode>()), new ConfigDescription("Toggles Deafen. Unbound by default to avoid conflicts with other mods.", (AcceptableValueBase)(object)new AcceptableShortcuts(), Array.Empty<object>()), synchronizedSetting: false);
			MonitorVolume = config("5 - Playback", "Monitor Volume", 0.7f, new ConfigDescription("How loudly you hear yourself while Hear Myself While I Talk is enabled.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>()), synchronizedSetting: false);
			JitterTargetMs = config("5 - Playback", "Jitter Buffer Target", 60, new ConfigDescription("Audio buffered to smooth out network hiccups. Lower means less delay; higher is more stable.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(20, 300), Array.Empty<object>()), synchronizedSetting: false);
			JitterMaxMs = config("5 - Playback", "Jitter Buffer Max", 200, new ConfigDescription("Maximum buffer size allowed when Automatic Voice Buffer is enabled.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(40, 600), Array.Empty<object>()), synchronizedSetting: false);
			AdaptiveJitter = config("5 - Playback", "Adaptive Jitter", Toggle.On, "Automatically adjusts each player's audio buffer based on their connection.", synchronizedSetting: false);
			DuckMusic = config("5 - Playback", "Duck Music", Toggle.On, "Lowers Valheim's music while a nearby player is speaking.", synchronizedSetting: false);
			DuckMusicAmount = config("5 - Playback", "Duck Music Amount", 0.35f, new ConfigDescription("Music volume while someone is speaking. 0 is silent, 1 is unchanged.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()), synchronizedSetting: false);
			Occlusion = config("5 - Playback", "Occlusion", Toggle.On, "Makes voices quieter and muffled when something solid is between you.", synchronizedSetting: false);
			OccludedCutoff = config("5 - Playback", "Occluded Cutoff", 900f, new ConfigDescription("How muffled voices sound through walls. Lower values sound more muffled.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(200f, 8000f), Array.Empty<object>()), synchronizedSetting: false);
			OccludedVolume = config("5 - Playback", "Occluded Volume", 0.7f, new ConfigDescription("Volume of voices heard through walls. 1 is full volume.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 1f), Array.Empty<object>()), synchronizedSetting: false);
			UnderwaterMuffle = config("5 - Playback", "Underwater Muffle", Toggle.On, "Muffles voice chat while you are swimming.", synchronizedSetting: false);
			UnderwaterCutoff = config("5 - Playback", "Underwater Cutoff", 500f, new ConfigDescription("How muffled voices sound underwater. Lower values sound more muffled.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(150f, 4000f), Array.Empty<object>()), synchronizedSetting: false);
			VoiceReverb = config("5 - Playback", "Voice Reverb", Toggle.Off, "Let the game's reverb zones colour voices, so caves and halls sound like caves and halls.", synchronizedSetting: false);
			ReverbMix = config("5 - Playback", "Reverb Mix", 0.3f, new ConfigDescription("How much of the game's reverb a voice picks up. A full send drowns speech in echo.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()), synchronizedSetting: false);
			ShowSpeakingIndicator = config("6 - UI", "Speaking Indicator", Toggle.On, "Shows a speaker icon above your character while you are transmitting.", synchronizedSetting: false);
			SpeakingIndicatorHeight = config("6 - UI", "Speaking Indicator Height", 0.5f, new ConfigDescription("How high the speaker icon sits above your head.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>()), synchronizedSetting: false);
			PeerIndicators = config("6 - UI", "Peer Speaking Indicators", Toggle.Off, "Shows a speaker icon above other players while they are talking.", synchronizedSetting: false);
			PeerIndicatorHeight = config("6 - UI", "Peer Indicator Height", 0.9f, new ConfigDescription("How high speaker icons sit above other players.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), Array.Empty<object>()), synchronizedSetting: false);
			PeerIndicatorScale = config("6 - UI", "Peer Indicator Scale", 1f, new ConfigDescription("Size of the speaker icons shown above other players.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.3f, 3f), Array.Empty<object>()), synchronizedSetting: false);
			PeerIndicatorThroughWalls = config("6 - UI", "Peer Indicator Through Walls", Toggle.Off, "Keeps speaking indicators visible even when a wall is between you.", synchronizedSetting: false);
			JawMovement = config("6 - UI", "Jaw Movement", Toggle.On, "Moves player jaws while they are speaking. Yours and others.", synchronizedSetting: false);
			JawMaxAngle = config("6 - UI", "Jaw Max Angle", 14f, new ConfigDescription("Maximum amount the jaw opens while speaking.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 40f), Array.Empty<object>()), synchronizedSetting: false);
			JawSensitivity = config("6 - UI", "Jaw Sensitivity", 12f, new ConfigDescription("How strongly voice volume moves the jaw. Raise this if mouths barely move.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 60f), Array.Empty<object>()), synchronizedSetting: false);
			JawAxis = config("6 - UI", "Jaw Axis", Bone.X, "Change this if the head twists instead of the mouth opening. Default is good for Valheim model, but might not be for VRMs", synchronizedSetting: false);
			HotkeyMessages = config("6 - UI", "Hotkey Messages", Toggle.On, "Shows a short message when you mute or deafen yourself with a hotkey.", synchronizedSetting: false);
			TestTone = config("6 - UI", "Test Tone", Toggle.Off, "Sends a test tone instead of microphone audio. Useful for testing without a working microphone.", synchronizedSetting: false);
			LoopbackTest = config("6 - UI", "Loopback Test", Toggle.Off, "Plays your outgoing voice back to you so you can hear what other players hear.", synchronizedSetting: false);
			PerPlayerSettings = config("6 - UI", "Per Player Settings", "", new ConfigDescription("Saved data. Don't write here manually, unless you know what you're doing. Written by the player list. steamid:volume:muted, semicolon separated.", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					Browsable = false
				}
			}), synchronizedSetting: false);
			TestTone.Value = Toggle.Off;
			LoopbackTest.Value = Toggle.Off;
			PeerPreferences.Load(PerPlayerSettings.Value);
			_harmony.PatchAll(Assembly.GetExecutingAssembly());
			_runtimeObject = new GameObject("ProximityVoiceChat_Runtime");
			Object.DontDestroyOnLoad((Object)(object)_runtimeObject);
			((Object)_runtimeObject).hideFlags = (HideFlags)61;
			_runtimeObject.AddComponent<VoiceRuntime>();
			_runtimeObject.AddComponent<SpeakingIndicator>();
			_runtimeObject.AddComponent<JawAnimator>();
			_runtimeObject.AddComponent<VoiceHotkeys>();
			UIRoot.Init(Log, _harmony);
			SetupWatcher();
			((BaseUnityPlugin)this).Config.Save();
			if (saveOnConfigSet)
			{
				((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet;
			}
		}

		private void OnDestroy()
		{
			if ((Object)(object)_runtimeObject != (Object)null)
			{
				Object.Destroy((Object)(object)_runtimeObject);
			}
			if (PeerPreferences.TryFlush(out string serialized))
			{
				PerPlayerSettings.Value = serialized;
			}
			((BaseUnityPlugin)this).Config.Save();
		}

		internal static void SaveConfig()
		{
			if (PeerPreferences.TryFlush(out string serialized))
			{
				PerPlayerSettings.Value = serialized;
			}
			ProximityVoiceChatPlugin? instance = Instance;
			if (instance != null)
			{
				((BaseUnityPlugin)instance).Config.Save();
			}
		}

		private void SetupWatcher()
		{
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName);
			fileSystemWatcher.Changed += ReadConfigValues;
			fileSystemWatcher.Created += ReadConfigValues;
			fileSystemWatcher.Renamed += ReadConfigValues;
			fileSystemWatcher.IncludeSubdirectories = true;
			fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher.EnableRaisingEvents = true;
		}

		private void ReadConfigValues(object sender, FileSystemEventArgs e)
		{
			if (!File.Exists(ConfigFileFullPath))
			{
				return;
			}
			try
			{
				Log.LogDebug((object)"ReadConfigValues called");
				((BaseUnityPlugin)this).Config.Reload();
			}
			catch
			{
				Log.LogError((object)("There was an issue loading your " + ConfigFileName));
				Log.LogError((object)"Please check your config entries for spelling and format!");
			}
		}

		private ConfigEntry<T> config<T>(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, description.Tags);
			ConfigEntry<T> val2 = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, val);
			ConfigSync.AddConfigEntry<T>(val2).SynchronizedConfig = synchronizedSetting;
			return val2;
		}

		private ConfigEntry<T> config<T>(string group, string name, T value, string description, bool synchronizedSetting = true)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting);
		}
	}
	public static class KeyboardExtensions
	{
		[SpecialName]
		public sealed class <G>$8D1D3E80A18AA9715780B6CB7003B2F1
		{
			[SpecialName]
			public static class <M>$895AB635D4D087636CF1C26BA650BA11
			{
			}

			[ExtensionMarker("<M>$895AB635D4D087636CF1C26BA650BA11")]
			public bool IsKeyDown()
			{
				throw null;
			}

			[ExtensionMarker("<M>$895AB635D4D087636CF1C26BA650BA11")]
			public bool IsKeyHeld()
			{
				throw null;
			}
		}

		public static bool IsKeyDown(this KeyboardShortcut shortcut)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey))
			{
				return ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func<KeyCode, bool>)Input.GetKey);
			}
			return false;
		}

		public static bool IsKeyHeld(this KeyboardShortcut shortcut)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey != 0 && Input.GetKey(((KeyboardShortcut)(ref shortcut)).MainKey))
			{
				return ((KeyboardShortcut)(ref shortcut)).Modifiers.All((Func<KeyCode, bool>)Input.GetKey);
			}
			return false;
		}
	}
	public static class ToggleExtensions
	{
		[SpecialName]
		public sealed class <G>$BDF3EF541E575CBEE3FDDD5BBDE7E281
		{
			[SpecialName]
			public static class <M>$E3FDBDD135D264042C5DDA2535FB9962
			{
			}

			[ExtensionMarker("<M>$E3FDBDD135D264042C5DDA2535FB9962")]
			public bool IsOn()
			{
				throw null;
			}

			[ExtensionMarker("<M>$E3FDBDD135D264042C5DDA2535FB9962")]
			public bool IsOff()
			{
				throw null;
			}
		}

		public static bool IsOn(this ProximityVoiceChatPlugin.Toggle toggle)
		{
			return toggle == ProximityVoiceChatPlugin.Toggle.On;
		}

		public static bool IsOff(this ProximityVoiceChatPlugin.Toggle toggle)
		{
			return toggle == ProximityVoiceChatPlugin.Toggle.Off;
		}
	}
}
namespace ProximityVoiceChat.UI
{
	internal static class SettingsTabInjector
	{
		internal const string TabLabel = "Voice";

		internal static void Inject(Settings? settings)
		{
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_0206: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Expected O, but got Unknown
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_026d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0272: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: Unknown result type (might be due to invalid IL or missing references)
			//IL_0281: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Expected O, but got Unknown
			//IL_0298: Expected O, but got Unknown
			if ((Object)(object)settings == (Object)null)
			{
				return;
			}
			TabHandler val = (((Object)(object)settings.m_tabHandler != (Object)null) ? settings.m_tabHandler : ((Component)settings).GetComponentInChildren<TabHandler>());
			if ((Object)(object)val == (Object)null)
			{
				ProximityVoiceChatPlugin.Log.LogWarning((object)"Voice tab: no TabHandler in the settings prefab");
				return;
			}
			if (val.m_tabs.Count == 0)
			{
				ProximityVoiceChatPlugin.Log.LogWarning((object)"Voice tab: settings prefab has no tabs");
				return;
			}
			foreach (Tab tab in val.m_tabs)
			{
				if ((Object)(object)tab.m_button != (Object)null && ((Object)tab.m_button).name == "Voice")
				{
					return;
				}
			}
			Button val2 = null;
			RectTransform val3 = null;
			foreach (Tab tab2 in val.m_tabs)
			{
				if ((Object)(object)tab2.m_button != (Object)null)
				{
					val2 = tab2.m_button;
				}
				if ((Object)(object)tab2.m_page != (Object)null && (Object)(object)val3 == (Object)null)
				{
					val3 = tab2.m_page;
				}
			}
			if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null)
			{
				ProximityVoiceChatPlugin.Log.LogWarning((object)$"Voice tab: no usable template, button {(Object)(object)val2 != (Object)null}, page {(Object)(object)val3 != (Object)null}");
				return;
			}
			Button val4 = Object.Instantiate<Button>(val2, ((Component)val2).transform.parent);
			((Object)val4).name = "Voice";
			((Component)val4).transform.SetAsLastSibling();
			((UnityEventBase)val4.onClick).RemoveAllListeners();
			SetLabel(((Component)val4).gameObject, "Voice");
			Transform val5 = ((Component)val4).transform.Find("KeyHint");
			if ((Object)(object)val5 != (Object)null)
			{
				((Component)val5).gameObject.SetActive(false);
			}
			GameObject val6 = new GameObject("VoicePage", new Type[1] { typeof(RectTransform) });
			val6.transform.SetParent(((Transform)val3).parent, false);
			RectTransform val7 = (RectTransform)val6.transform;
			val7.anchorMin = val3.anchorMin;
			val7.anchorMax = val3.anchorMax;
			val7.pivot = val3.pivot;
			val7.offsetMin = val3.offsetMin;
			val7.offsetMax = val3.offsetMax;
			((Transform)val7).localScale = Vector3.one;
			val6.AddComponent<VoiceSettingsTab>();
			val6.SetActive(false);
			val.m_tabs.Add(new Tab
			{
				m_button = val4,
				m_page = val7,
				m_default = false,
				m_onClick = new UnityEvent()
			});
			ProximityVoiceChatPlugin.Log.LogInfo((object)$"Added the Voice tab to the settings menu, {val.m_tabs.Count} tabs now");
		}

		private static void SetLabel(GameObject button, string text)
		{
			TMP_Text[] componentsInChildren = button.GetComponentsInChildren<TMP_Text>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].text = text;
			}
			Text[] componentsInChildren2 = button.GetComponentsInChildren<Text>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				componentsInChildren2[i].text = text;
			}
			Localize[] componentsInChildren3 = button.GetComponentsInChildren<Localize>(true);
			for (int j = 0; j < componentsInChildren3.Length; j++)
			{
				Object.Destroy((Object)(object)componentsInChildren3[j]);
			}
		}
	}
	[HarmonyPatch(typeof(Settings), "SetAvailableTabs")]
	internal static class Settings_SetAvailableTabs_Patch
	{
		private static void Prefix(Settings __instance)
		{
			try
			{
				SettingsTabInjector.Inject(__instance);
			}
			catch (Exception arg)
			{
				ProximityVoiceChatPlugin.Log.LogError((object)$"Could not add the Voice settings tab: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(SessionPlayerListEntry), "SetValues")]
	internal static class SessionPlayerListEntry_SetValues_Patch
	{
		private static void Postfix(SessionPlayerListEntry __instance)
		{
			VoiceEntryUI voiceEntryUI = ((Component)__instance).gameObject.GetComponent<VoiceEntryUI>();
			if ((Object)(object)voiceEntryUI == (Object)null)
			{
				voiceEntryUI = ((Component)__instance).gameObject.AddComponent<VoiceEntryUI>();
			}
			voiceEntryUI.Bind(__instance, __instance.IsOwnPlayer);
		}
	}
	internal sealed class SliderRow
	{
		internal Slider Slider;

		internal Text Value;

		internal string Format = "0.00";

		internal void Set(float value)
		{
			Slider.SetValueWithoutNotify(value);
			Value.text = value.ToString(Format);
		}
	}
	internal sealed class KeyRow
	{
		internal Button Button;

		internal Text Label;

		internal ConfigEntry<KeyboardShortcut> Entry;

		internal void Refresh()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			Label.text = (KeyBinder.IsListening(Entry) ? UIBuild.Localize("$pvc_key_press") : KeyBinder.Describe(Entry.Value));
		}
	}
	internal sealed class CycleRow<T> where T : struct, Enum
	{
		internal Button Button;

		internal Text Label;

		internal ConfigEntry<T> Entry;

		internal void Step()
		{
			T[] array = (T[])Enum.GetValues(typeof(T));
			int num = Array.IndexOf(array, Entry.Value);
			Entry.Value = array[(num + 1 + array.Length) % array.Length];
			Refresh();
		}

		internal void Refresh()
		{
			Label.text = Entry.Value.ToString();
		}
	}
	internal static class UIBuild
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UnityAction <>9__42_0;

			public static UnityAction <>9__42_1;

			internal void <DevicePicker>b__42_0()
			{
				StepDevice(-1);
			}

			internal void <DevicePicker>b__42_1()
			{
				StepDevice(1);
			}
		}

		internal const float RowHeight = 26f;

		internal const float LabelWidth = 210f;

		internal const float ValueWidth = 56f;

		private const float RowSpacing = 10f;

		private const float HeadingHeight = 28f;

		private const float NoteHeight = 20f;

		private const float ControlHeight = 24f;

		private const float ToggleHeight = 22f;

		private const float SliderHeight = 18f;

		private const float SliderWidth = 200f;

		private const float ButtonWidth = 160f;

		internal const float TallRowHeight = 28f;

		private const float ArrowWidth = 28f;

		private const float ArrowCell = 32f;

		private const float MeterRowHeight = 20f;

		private const float MeterLabelWidth = 70f;

		private const float MeterTrackWidth = 200f;

		private const float MeterTrackHeight = 12f;

		private const int BodyFontSize = 16;

		private const int TitleFontSize = 18;

		private const int NoteFontSize = 15;

		private const int SmallFontSize = 14;

		internal const float MeterFloorDb = -60f;

		private const float MeterSilence = 0.0001f;

		private const float AmplitudeToDb = 20f;

		internal static string Localize(string key)
		{
			if (Localization.instance == null)
			{
				return key;
			}
			return Localization.instance.Localize(key);
		}

		internal static string Localize(string key, params object[] args)
		{
			return string.Format(Localize(key), args);
		}

		internal static GameObject Row(Transform parent, float height)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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_0071: Expected O, but got Unknown
			GameObject val = new GameObject("Row", new Type[1] { typeof(RectTransform) });
			val.transform.SetParent(parent, false);
			HorizontalLayoutGroup obj = val.AddComponent<HorizontalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj).spacing = 10f;
			((LayoutGroup)obj).childAlignment = (TextAnchor)3;
			((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = false;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false;
			LayoutElement obj2 = val.AddComponent<LayoutElement>();
			obj2.minHeight = height;
			obj2.preferredHeight = height;
			return val;
		}

		internal static LayoutElement Element(Component component)
		{
			LayoutElement component2 = component.gameObject.GetComponent<LayoutElement>();
			if (!((Object)(object)component2 != (Object)null))
			{
				return component.gameObject.AddComponent<LayoutElement>();
			}
			return component2;
		}

		internal static T Fixed<T>(T component, float width, float height = 0f) where T : Component
		{
			LayoutElement val = Element((Component)(object)component);
			val.minWidth = width;
			val.preferredWidth = width;
			if (height > 0f)
			{
				val.minHeight = height;
				val.preferredHeight = height;
			}
			return component;
		}

		internal static T Flex<T>(T component) where T : Component
		{
			Element((Component)(object)component).flexibleWidth = 1f;
			return component;
		}

		internal static Text Label(Transform parent, string text)
		{
			return UIFactory.Text("Label", parent, text, TextRole.Body, 16, (TextAnchor)3);
		}

		internal static Text Heading(Transform parent, string text)
		{
			Text obj = UIFactory.Text("Heading", parent, text, TextRole.Title, 18, (TextAnchor)3);
			Element((Component)(object)obj).preferredHeight = 28f;
			return obj;
		}

		internal static Text Note(Transform parent, string text)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			Text obj = UIFactory.Text("Note", parent, text, TextRole.Body, 15, (TextAnchor)3);
			((Graphic)obj).color = GameColors.Beige;
			Element((Component)(object)obj).preferredHeight = 20f;
			return obj;
		}

		internal static float MeterScale(float amplitude)
		{
			if (amplitude <= 0.0001f)
			{
				return 0f;
			}
			return Mathf.Clamp01((20f * Mathf.Log10(amplitude) - -60f) / 60f);
		}

		internal static RectTransform Meter(Transform parent, string label)
		{
			//IL_0046: 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_00ab: Expected O, but got Unknown
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: 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_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Expected O, but got Unknown
			GameObject val = Row(parent, 20f);
			UIBuild.Fixed<Text>(UIFactory.Text("Label", val.transform, label, TextRole.Body, 14, (TextAnchor)3), 70f, 0f);
			GameObject val2 = UIFactory.Panel("Track", val.transform, new Vector2(200f, 12f), window: false);
			UIBuild.Flex<Transform>(val2.transform);
			Element((Component)(object)val2.transform).preferredHeight = 12f;
			GameObject val3 = new GameObject("Fill", new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			val3.transform.SetParent(val2.transform, false);
			RectTransform val4 = (RectTransform)val3.transform;
			val4.anchorMin = Vector2.zero;
			val4.anchorMax = new Vector2(0f, 1f);
			val4.pivot = new Vector2(0f, 0.5f);
			val4.offsetMin = Vector2.zero;
			val4.offsetMax = Vector2.zero;
			((Graphic)val3.GetComponent<Image>()).color = GameColors.Beige;
			return val4;
		}

		internal static SliderRow SliderControl(Transform parent, string label, float min, float max, float value, UnityAction<float> onChanged, string format = "0.00")
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = Row(parent, 26f);
			UIBuild.Fixed<Text>(Label(val.transform, label), 210f, 0f);
			SliderRow control = new SliderRow
			{
				Format = format
			};
			control.Slider = UIFactory.Slider(label, val.transform, new Vector2(200f, 18f), min, max, value, delegate(float v)
			{
				onChanged.Invoke(v);
				control.Value.text = v.ToString(control.Format);
			});
			UIBuild.Flex<Slider>(control.Slider);
			Element((Component)(object)control.Slider).preferredHeight = 18f;
			control.Value = UIBuild.Fixed<Text>(UIFactory.Text("Value", val.transform, value.ToString(format), TextRole.Body, 16, (TextAnchor)5), 56f, 0f);
			return control;
		}

		internal static SliderRow SliderFor(Transform parent, string label, ConfigEntry<float> entry, string format = "0.00")
		{
			AcceptableValueRange<float> val = (AcceptableValueRange<float>)(object)((ConfigEntryBase)entry).Description.AcceptableValues;
			return SliderControl(parent, label, val.MinValue, val.MaxValue, entry.Value, delegate(float v)
			{
				if (!Mathf.Approximately(entry.Value, v))
				{
					entry.Value = v;
				}
			}, format);
		}

		internal static Toggle ToggleFor(Transform parent, string label, ConfigEntry<ProximityVoiceChatPlugin.Toggle> entry)
		{
			return RawToggle(parent, label, entry.Value.IsOn(), delegate(bool on)
			{
				entry.Value = (on ? ProximityVoiceChatPlugin.Toggle.On : ProximityVoiceChatPlugin.Toggle.Off);
			});
		}

		internal static Toggle RawToggle(Transform parent, string label, bool value, UnityAction<bool> onChanged)
		{
			GameObject val = Row(parent, 26f);
			Toggle obj = UIFactory.Toggle(label, val.transform, label, value, onChanged);
			UIBuild.Flex<Toggle>(obj);
			Element((Component)(object)obj).preferredHeight = 22f;
			return obj;
		}

		internal static KeyRow KeyBinding(Transform parent, string label, ConfigEntry<KeyboardShortcut> entry)
		{
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			GameObject val = Row(parent, 26f);
			UIBuild.Fixed<Text>(Label(val.transform, label), 210f, 0f);
			KeyRow obj = new KeyRow
			{
				Entry = entry,
				Button = UIBuild.Flex<Button>(UIFactory.Button("Bind", val.transform, KeyBinder.Describe(entry.Value), new Vector2(160f, 24f), (UnityAction)delegate
				{
					KeyBinder.Begin(entry);
				}))
			};
			Element((Component)(object)obj.Button).preferredHeight = 24f;
			obj.Label = ((Component)obj.Button).GetComponentInChildren<Text>();
			return obj;
		}

		internal static CycleRow<T> Cycle<T>(Transform parent, string label, ConfigEntry<T> entry) where T : struct, Enum
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			GameObject val = Row(parent, 26f);
			UIBuild.Fixed<Text>(Label(val.transform, label), 210f, 0f);
			CycleRow<T> cycleRow = new CycleRow<T>
			{
				Entry = entry
			};
			cycleRow.Button = UIBuild.Flex<Button>(UIFactory.Button("Cycle", val.transform, entry.Value.ToString(), new Vector2(160f, 24f), new UnityAction(cycleRow.Step)));
			Element((Component)(object)cycleRow.Button).preferredHeight = 24f;
			cycleRow.Label = ((Component)cycleRow.Button).GetComponentInChildren<Text>();
			return cycleRow;
		}

		internal static Text DevicePicker(Transform parent, string label)
		{
			//IL_0042: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Expected O, but got Unknown
			GameObject val = Row(parent, 28f);
			UIBuild.Fixed<Text>(Label(val.transform, label), 210f, 0f);
			Transform transform = val.transform;
			Vector2 size = new Vector2(28f, 24f);
			object obj = <>c.<>9__42_0;
			if (obj == null)
			{
				UnityAction val2 = delegate
				{
					StepDevice(-1);
				};
				<>c.<>9__42_0 = val2;
				obj = (object)val2;
			}
			UIBuild.Fixed<Button>(UIFactory.Button("Prev", transform, "<", size, (UnityAction)obj), 32f, 24f);
			Text result = UIBuild.Flex<Text>(UIFactory.Text("Device", val.transform, "", TextRole.Body, 16, (TextAnchor)4));
			Transform transform2 = val.transform;
			Vector2 size2 = new Vector2(28f, 24f);
			object obj2 = <>c.<>9__42_1;
			if (obj2 == null)
			{
				UnityAction val3 = delegate
				{
					StepDevice(1);
				};
				<>c.<>9__42_1 = val3;
				obj2 = (object)val3;
			}
			UIBuild.Fixed<Button>(UIFactory.Button("Next", transform2, ">", size2, (UnityAction)obj2), 32f, 24f);
			return result;
		}

		internal static void StepDevice(int direction)
		{
			string[] devices = MicrophoneCapture.Devices;
			if (devices.Length != 0)
			{
				int num = Array.IndexOf(devices, ProximityVoiceChatPlugin.InputDevice.Value);
				if (num < 0)
				{
					num = 0;
				}
				num = (num + direction + devices.Length) % devices.Length;
				ProximityVoiceChatPlugin.InputDevice.Value = devices[num];
			}
		}

		internal static string CurrentDeviceName()
		{
			string value = ProximityVoiceChatPlugin.InputDevice.Value;
			if (!string.IsNullOrEmpty(value))
			{
				return value;
			}
			string[] devices = MicrophoneCapture.Devices;
			if (devices.Length == 0)
			{
				return Localize("$pvc_device_none");
			}
			return devices[0];
		}
	}
	internal sealed class VoiceSettingsTab : MonoBehaviour, ISettingsTab
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UnityAction<bool> <>9__45_0;

			public static UnityAction <>9__45_1;

			internal void <Build>b__45_0(bool on)
			{
				ProximityVoiceChatPlugin.LoopbackTest.Value = (on ? ProximityVoiceChatPlugin.Toggle.On : ProximityVoiceChatPlugin.Toggle.Off);
			}

			internal void <Build>b__45_1()
			{
				VoiceRuntime.Instance?.Capture?.ProbeRaw();
			}
		}

		private Text? _device;

		private Text? _status;

		private RectTransform? _inFill;

		private RectTransform? _rmsFill;

		private RectTransform? _outFill;

		private Text? _numbers;

		private Text? _stats;

		private SliderRow? _gain;

		private SliderRow? _gate;

		private SliderRow? _incoming;

		private SliderRow? _monitor;

		private Toggle? _enableVoice;

		private Toggle? _activation;

		private Toggle? _muteSelf;

		private Toggle? _deafen;

		private Toggle? _monitorOn;

		private Toggle? _autoGain;

		private Toggle? _duckMusic;

		private Toggle? _adaptiveJitter;

		private Toggle? _testTone;

		private Toggle? _speakingIndicator;

		private Toggle? _peerIndicators;

		private Toggle? _peerThroughWalls;

		private Toggle? _jawMovement;

		private Toggle? _occlusion;

		private Toggle? _underwater;

		private Toggle? _reverb;

		private SliderRow? _selfHeight;

		private SliderRow? _peerHeight;

		private SliderRow? _peerScale;

		private SliderRow? _jawAngle;

		private SliderRow? _jawSensitivity;

		private CycleRow<ProximityVoiceChatPlugin.Bone>? _jawAxis;

		private readonly List<KeyRow> _keyRows = new List<KeyRow>();

		private const float TextInterval = 0.15f;

		private const int ClipWarningFrames = 50;

		private const int ContentPadding = 24;

		private const float ContentSpacing = 6f;

		private const float ProbeButtonWidth = 220f;

		private const float ProbeButtonHeight = 26f;

		private float _textTimer;

		public event Action<string, int>? SharedSettingChanged;

		public void Initialize()
		{
			try
			{
				Build();
			}
			catch (Exception arg)
			{
				ProximityVoiceChatPlugin.Log.LogError((object)$"Voice settings tab failed to build: {arg}");
			}
		}

		private void Build()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: 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_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			//IL_051d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0536: Unknown result type (might be due to invalid IL or missing references)
			//IL_053b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0541: Expected O, but got Unknown
			RectTransform content;
			RectTransform val = (RectTransform)((Component)UIFactory.ScrollView("VoiceScroll", ((Component)this).transform, new Vector2(100f, 100f), out content)).transform;
			val.anchorMin = Vector2.zero;
			val.anchorMax = Vector2.one;
			val.offsetMin = Vector2.zero;
			val.offsetMax = Vector2.zero;
			Transform parent = (Transform)(object)content;
			VerticalLayoutGroup component = ((Component)content).GetComponent<VerticalLayoutGroup>();
			if (component != null)
			{
				((LayoutGroup)component).padding = new RectOffset(24, 24, 24, 24);
				((HorizontalOrVerticalLayoutGroup)component).spacing = 6f;
				((HorizontalOrVerticalLayoutGroup)component).childControlWidth = true;
				((HorizontalOrVerticalLayoutGroup)component).childForceExpandWidth = true;
				((HorizontalOrVerticalLayoutGroup)component).childControlHeight = true;
				((HorizontalOrVerticalLayoutGroup)component).childForceExpandHeight = false;
			}
			UIBuild.Heading(parent, UIBuild.Localize("$pvc_heading_microphone"));
			_enableVoice = UIBuild.ToggleFor(parent, UIBuild.Localize("$pvc_enable_voice"), ProximityVoiceChatPlugin.EnableVoice);
			_status = UIBuild.Note(parent, "");
			_device = UIBuild.DevicePicker(parent, UIBuild.Localize("$pvc_input_device"));
			_inFill = UIBuild.Meter(parent, UIBuild.Localize("$pvc_meter_input"));
			_rmsFill = UIBuild.Meter(parent, UIBuild.Localize("$pvc_meter_sent"));
			_outFill = UIBuild.Meter(parent, UIBuild.Localize("$pvc_meter_heard"));
			_numbers = UIBuild.Note(parent, "");
			_gain = UIBuild.SliderFor(parent, UIBuild.Localize("$pvc_mic_gain"), ProximityVoiceChatPlugin.MicGain);
			_gate = UIBuild.SliderFor(parent, UIBuild.Localize("$pvc_gate_threshold"), ProximityVoiceChatPlugin.ActivationThreshold, "0.000");
			_activation = UIBuild.ToggleFor(parent, UIBuild.Localize("$pvc_voice_activation"), ProximityVoiceChatPlugin.UseVoiceActivation);
			_autoGain = UIBuild.ToggleFor(parent, UIBuild.Localize("$pvc_auto_gain"), ProximityVoiceChatPlugin.AutoGain);
			_muteSelf = UIBuild.ToggleFor(parent, UIBuild.Localize("$pvc_mute_self"), ProximityVoiceChatPlugin.MuteSelf);
			UIBuild.Heading(parent, UIBuild.Localize("$pvc_heading_listening"));
			_incoming = UIBuild.SliderFor(parent, UIBuild.Localize("$pvc_incoming_volume"), ProximityVoiceChatPlugin.VoiceVolume);
			_deafen = UIBuild.ToggleFor(parent, UIBuild.Localize("$pvc_deafen"), ProximityVoiceChatPlugin.Deafen);
			_duckMusic = UIBuild.ToggleFor(parent, UIBuild.Localize("$pvc_duck_music"), ProximityVoiceChatPlugin.DuckMusic);
			_adaptiveJitter = UIBuild.ToggleFor(parent, UIBuild.Localize("$pvc_adaptive_jitter"), ProximityVoiceChatPlugin.AdaptiveJitter);
			_occlusion = UIBuild.ToggleFor(parent, UIBuild.Localize("$pvc_occlusion"), ProximityVoiceChatPlugin.Occlusion);
			_underwater = UIBuild.ToggleFor(parent, UIBuild.Localize("$pvc_underwater"), ProximityVoiceChatPlugin.UnderwaterMuffle);
			_reverb = UIBuild.ToggleFor(parent, UIBuild.Localize("$pvc_reverb"), ProximityVoiceChatPlugin.VoiceReverb);
			UIBuild.Heading(parent, UIBuild.Localize("$pvc_heading_keys"));
			_keyRows.Add(UIBuild.KeyBinding(parent, UIBuild.Localize("$pvc_key_ptt"), ProximityVoiceChatPlugin.PushToTalkKey));
			_keyRows.Add(UIBuild.KeyBinding(parent, UIBuild.Localize("$pvc_key_mute"), ProximityVoiceChatPlugin.MuteSelfKey));
			_keyRows.Add(UIBuild.KeyBinding(parent, UIBuild.Localize("$pvc_key_deafen"), ProximityVoiceChatPlugin.DeafenKey));
			UIBuild.Note(parent, UIBuild.Localize("$pvc_note_binding"));
			UIBuild.Heading(parent, UIBuild.Localize("$pvc_heading_interface"));
			_speakingIndicator = UIBuild.ToggleFor(parent, UIBuild.Localize("$pvc_speaking_indicator"), ProximityVoiceChatPlugin.ShowSpeakingIndicator);
			_selfHeight = UIBuild.SliderFor(parent, UIBuild.Localize("$pvc_indicator_height"), ProximityVoiceChatPlugin.SpeakingIndicatorHeight);
			_peerIndicators = UIBuild.ToggleFor(parent, UIBuild.Localize("$pvc_peer_indicators"), ProximityVoiceChatPlugin.PeerIndicators);
			_peerHeight = UIBuild.SliderFor(parent, UIBuild.Localize("$pvc_peer_indicator_height"), ProximityVoiceChatPlugin.PeerIndicatorHeight);
			_peerScale = UIBuild.SliderFor(parent, UIBuild.Localize("$pvc_peer_indicator_scale"), ProximityVoiceChatPlugin.PeerIndicatorScale);
			_peerThroughWalls = UIBuild.ToggleFor(parent, UIBuild.Localize("$pvc_peer_through_walls"), ProximityVoiceChatPlugin.PeerIndicatorThroughWalls);
			_jawMovement = UIBuild.ToggleFor(parent, UIBuild.Localize("$pvc_jaw_movement"), ProximityVoiceChatPlugin.JawMovement);
			_jawAngle = UIBuild.SliderFor(parent, UIBuild.Localize("$pvc_jaw_angle"), ProximityVoiceChatPlugin.JawMaxAngle, "0");
			_jawSensitivity = UIBuild.SliderFor(parent, UIBuild.Localize("$pvc_jaw_sensitivity"), ProximityVoiceChatPlugin.JawSensitivity, "0");
			_jawAxis = UIBuild.Cycle<ProximityVoiceChatPlugin.Bone>(parent, UIBuild.Localize("$pvc_jaw_axis"), ProximityVoiceChatPlugin.JawAxis);
			UIBuild.Heading(parent, UIBuild.Localize("$pvc_heading_test"));
			_monitor = UIBuild.SliderFor(parent, UIBuild.Localize("$pvc_monitor_volume"), ProximityVoiceChatPlugin.MonitorVolume);
			_monitorOn = UIBuild.RawToggle(parent, UIBuild.Localize("$pvc_hear_myself"), ProximityVoiceChatPlugin.LoopbackTest.Value.IsOn(), delegate(bool on)
			{
				ProximityVoiceChatPlugin.LoopbackTest.Value = (on ? ProximityVoiceChatPlugin.Toggle.On : ProximityVoiceChatPlugin.Toggle.Off);
			});
			_testTone = UIBuild.ToggleFor(parent, UIBuild.Localize("$pvc_test_tone"), ProximityVoiceChatPlugin.TestTone);
			GameObject val2 = UIBuild.Row(parent, 28f);
			Transform transform = val2.transform;
			string label = UIBuild.Localize("$pvc_probe_button");
			Vector2 size = new Vector2(220f, 26f);
			object obj = <>c.<>9__45_1;
			if (obj == null)
			{
				UnityAction val3 = delegate
				{
					VoiceRuntime.Instance?.Capture?.ProbeRaw();
				};
				<>c.<>9__45_1 = val3;
				obj = (object)val3;
			}
			UIBuild.Flex<Button>(UIFactory.Button("Probe", transform, label, size, (UnityAction)obj));
			_stats = UIBuild.Note(parent, "");
			UIBuild.Note(parent, UIBuild.Localize("$pvc_note_perplayer"));
			UIBuild.Note(parent, UIBuild.Localize("$pvc_note_menu_mic"));
		}

		public void OnTabOpen(Button backButton, Button okButton)
		{
		}

		private void OnEnable()
		{
			VoiceRuntime.LocalTestRequested = true;
		}

		private void OnDisable()
		{
			VoiceRuntime.LocalTestRequested = false;
			KeyBinder.Cancel();
		}

		public void OnOkAsync(OkActionCompletedHandler okActionCompletedCallback)
		{
			ProximityVoiceChatPlugin.SaveConfig();
			if (okActionCompletedCallback != null)
			{
				okActionCompletedCallback.Invoke();
			}
		}

		private void Update()
		{
			KeyBinder.Tick();
			for (int i = 0; i < _keyRows.Count; i++)
			{
				_keyRows[i].Refresh();
			}
			VoiceRuntime instance = VoiceRuntime.Instance;
			MicrophoneCapture microphoneCapture = instance?.Capture;
			VoiceEncoder voiceEncoder = instance?.Encoder;
			float num = 0f;
			if (instance?.Playback != null && instance.Playback.Streams.TryGetValue(1uL, out PeerVoiceStream value))
			{
				num = value.OutputRms;
			}
			SetFill(_inFill, microphoneCapture?.PeakLevel ?? 0f);
			SetFill(_rmsFill, voiceEncoder?.LastRms ?? 0f);
			SetFill(_outFill, num);
			_textTimer += Time.unscaledDeltaTime;
			if (_textTimer >= 0.15f)
			{
				_textTimer = 0f;
				RefreshText(microphoneCapture, voiceEncoder, instance, num);
			}
			_gain?.Set(ProximityVoiceChatPlugin.MicGain.Value);
			_gate?.Set(ProximityVoiceChatPlugin.ActivationThreshold.Value);
			_incoming?.Set(ProximityVoiceChatPlugin.VoiceVolume.Value);
			_monitor?.Set(ProximityVoiceChatPlugin.MonitorVolume.Value);
			_selfHeight?.Set(ProximityVoiceChatPlugin.SpeakingIndicatorHeight.Value);
			_peerHeight?.Set(ProximityVoiceChatPlugin.PeerIndicatorHeight.Value);
			_peerScale?.Set(ProximityVoiceChatPlugin.PeerIndicatorScale.Value);
			_jawAngle?.Set(ProximityVoiceChatPlugin.JawMaxAngle.Value);
			_jawSensitivity?.Set(ProximityVoiceChatPlugin.JawSensitivity.Value);
			_jawAxis?.Refresh();
			SetToggle(_enableVoice, ProximityVoiceChatPlugin.EnableVoice);
			SetToggle(_activation, ProximityVoiceChatPlugin.UseVoiceActivation);
			SetToggle(_muteSelf, ProximityVoiceChatPlugin.MuteSelf);
			SetToggle(_deafen, ProximityVoiceChatPlugin.Deafen);
			SetToggle(_monitorOn, ProximityVoiceChatPlugin.LoopbackTest);
			SetToggle(_autoGain, ProximityVoiceChatPlugin.AutoGain);
			SetToggle(_duckMusic, ProximityVoiceChatPlugin.DuckMusic);
			SetToggle(_adaptiveJitter, ProximityVoiceChatPlugin.AdaptiveJitter);
			SetToggle(_testTone, ProximityVoiceChatPlugin.TestTone);
			SetToggle(_speakingIndicator, ProximityVoiceChatPlugin.ShowSpeakingIndicator);
			SetToggle(_peerIndicators, ProximityVoiceChatPlugin.PeerIndicators);
			SetToggle(_peerThroughWalls, ProximityVoiceChatPlugin.PeerIndicatorThroughWalls);
			SetToggle(_jawMovement, ProximityVoiceChatPlugin.JawMovement);
			SetToggle(_occlusion, ProximityVoiceChatPlugin.Occlusion);
			SetToggle(_underwater, ProximityVoiceChatPlugin.UnderwaterMuffle);
			SetToggle(_reverb, ProximityVoiceChatPlugin.VoiceReverb);
		}

		private void RefreshText(MicrophoneCapture? capture, VoiceEncoder? encoder, VoiceRuntime? runtime, float heard)
		{
			if ((Object)(object)_device != (Object)null)
			{
				_device.text = UIBuild.CurrentDeviceName();
			}
			if ((Object)(object)_status != (Object)null)
			{
				_status.text = ((capture == null) ? UIBuild.Localize("$pvc_no_microphone") : UIBuild.Localize("$pvc_status_device", capture.Device ?? "", capture.DeviceRate, capture.Channels));
			}
			if ((Object)(object)_stats != (Object)null)
			{
				SteamVoiceTransport steamVoiceTransport = runtime?.Transport;
				_stats.text = ((steamVoiceTransport == null) ? UIBuild.Localize("$pvc_not_connected") : UIBuild.Localize("$pvc_stats", steamVoiceTransport.PacketsSent, steamVoiceTransport.PacketsReceived, steamVoiceTransport.PacketsDropped));
			}
			if (!((Object)(object)_numbers == (Object)null))
			{
				string text = ((encoder != null && encoder.FramesSinceClip < 50) ? ("   <color=#ff8080>" + UIBuild.Localize("$pvc_too_loud") + "</color>") : "");
				_numbers.text = UIBuild.Localize("$pvc_numbers", (capture?.PeakLevel ?? 0f).ToString("0.000"), (encoder?.LastRms ?? 0f).ToString("0.000"), heard.ToString("0.000"), (-60f).ToString("0")) + text;
			}
		}

		private static void SetFill(RectTransform? fill, float value)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)fill != (Object)null)
			{
				fill.anchorMax = new Vector2(UIBuild.MeterScale(value), 1f);
			}
		}

		private static void SetToggle(Toggle? toggle, ConfigEntry<ProximityVoiceChatPlugin.Toggle> entry)
		{
			if ((Object)(object)toggle != (Object)null)
			{
				toggle.SetIsOnWithoutNotify(entry.Value.IsOn());
			}
		}
	}
	internal sealed class VoiceEntryUI : MonoBehaviour
	{
		private static readonly Color Speaking = new Color(0.45f, 1f, 0.45f, 1f);

		private static readonly Color Silent = new Color(1f, 1f, 1f, 0.55f);

		private static readonly Color Blocked = new Color(1f, 0.45f, 0.45f, 1f);

		private const float FallbackSpacing = -60f;

		private const float IconSize = 48f;

		private const float Gap = 12f;

		private const float RefreshInterval = 0.1f;

		private const float ExtraHeight = 40f;

		private const float LabelWidth = 64f;

		private const float SliderWidth = 296f;

		private const float SliderHeight = 14f;

		private const float ValueWidth = 46f;

		private const float TextHeight = 20f;

		private const int FontSize = 14;

		private const float DefaultNameLeft = 76f;

		private const float DefaultNameBottom = -28f;

		private static bool _warned;

		private Image? _icon;

		private Slider? _volume;

		private Text? _volumeText;

		private ulong _steamId;

		private bool _own;

		private bool _suppress;

		private float _timer;

		internal void Bind(SessionPlayerListEntry entry, bool isOwnPlayer)
		{
			//IL_0008: 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_0030: Expected O, but got Unknown
			_own = isOwnPlayer;
			if (PeerPreferences.TryGetSteamId(entry.User, out _steamId))
			{
				VoiceSprites.Resolve();
				GrowRow((RectTransform)((Component)entry).transform);
				BuildMute(entry);
				BuildVolume(entry);
				Refresh();
			}
		}

		private void BuildMute(SessionPlayerListEntry entry)
		{
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Expected O, but got Unknown
			if ((Object)(object)_icon != (Object)null)
			{
				return;
			}
			Transform val = ((Component)entry).transform.Find("PVC_MuteImage");
			if ((Object)(object)val != (Object)null)
			{
				_icon = ((Component)val).GetComponent<Image>();
				Wire((val.childCount > 0) ? ((Component)val.GetChild(0)).GetComponent<Button>() : null);
				return;
			}
			Transform val2 = ((Component)entry).transform.Find("MuteImage");
			if ((Object)(object)val2 != (Object)null)
			{
				((Component)val2).gameObject.SetActive(true);
				_icon = ((Component)val2).GetComponent<Image>();
				Transform obj = val2.Find("Mute");
				Wire((obj != null) ? ((Component)obj).GetComponent<Button>() : null);
				return;
			}
			Transform obj2 = ((Component)entry).transform.Find("BlockImage");
			RectTransform val3 = (RectTransform)(object)((obj2 is RectTransform) ? obj2 : null);
			Transform obj3 = ((Component)entry).transform.Find("KickImage");
			RectTransform val4 = (RectTransform)(object)((obj3 is RectTransform) ? obj3 : null);
			if ((Object)(object)val3 == (Object)null)
			{
				if (!_warned)
				{
					_warned = true;
					ProximityVoiceChatPlugin.Log.LogWarning((object)"No BlockImage on the player list row, so there is nothing to clone a mute button from. Player list voice controls are off.");
				}
				return;
			}
			float num = (((Object)(object)val4 != (Object)null) ? (val3.anchoredPosition.x - val4.anchoredPosition.x) : (-60f));
			GameObject val5 = Object.Instantiate<GameObject>(((Component)val3).gameObject, ((Component)entry).transform);
			((Object)val5).name = "PVC_MuteImage";
			val5.SetActive(true);
			Pin((RectTransform)val5.transform, val3.anchoredPosition.x + num, 48f, 48f);
			_icon = val5.GetComponent<Image>();
			Transform val6 = ((val5.transform.childCount > 0) ? val5.transform.GetChild(0) : null);
			if ((Object)(object)val6 != (Object)null)
			{
				((Object)val6).name = "PVC_Mute";
				Wire(((Component)val6).GetComponent<Button>());
			}
		}

		private void Wire(Button? button)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			if (!((Object)(object)button == (Object)null))
			{
				for (int i = 0; i < ((UnityEventBase)button.onClick).GetPersistentEventCount(); i++)
				{
					((UnityEventBase)button.onClick).SetPersistentListenerState(i, (UnityEventCallState)0);
				}
				((UnityEventBase)button.onClick).RemoveAllListeners();
				((UnityEvent)button.onClick).AddListener(new UnityAction(OnClick));
			}
		}

		private void BuildVolume(SessionPlayerListEntry entry)
		{
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Expected O, but got Unknown
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Expected O, but got Unknown
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: 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_01a9: Expected O, but got Unknown
			//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Expected O, but got Unknown
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			if (_own || (Object)(object)_volume != (Object)null)
			{
				return;
			}
			Slider val = ((IEnumerable<Slider>)((Component)entry).GetComponentsInChildren<Slider>(true)).FirstOrDefault((Func<Slider, bool>)((Slider x) => ((Object)x).name == "PVC_Volume"));
			if ((Object)(object)val != (Object)null)
			{
				_volume = val;
				Transform obj = ((Component)val).transform.parent.Find("PVC_VolumeValue");
				_volumeText = ((obj != null) ? ((Component)obj).GetComponent<Text>() : null);
				((UnityEventBase)_volume.onValueChanged).RemoveAllListeners();
				((UnityEvent<float>)(object)_volume.onValueChanged).AddListener((UnityAction<float>)OnVolumeChanged);
				return;
			}
			RectTransform val2 = (RectTransform)((Component)entry).transform;
			Transform obj2 = ((Component)entry).transform.Find("Background");
			RectTransform val3 = (RectTransform)(object)((obj2 is RectTransform) ? obj2 : null);
			if (!((Object)(object)val3 == (Object)null))
			{
				float y = (NameBottomEdge(val2) - val2.sizeDelta.y * 0.5f) * 0.5f;
				float num = NameLeftEdge(val2);
				Text obj3 = UIFactory.Text("PVC_VolumeLabel", (Transform)(object)val3, UIBuild.Localize("$pvc_volume_label"), TextRole.Body, 14, (TextAnchor)3);
				PinLeft((RectTransform)((Component)obj3).transform, num, y, 64f, 20f);
				((Graphic)obj3).color = GameColors.Muted;
				_volume = UIFactory.Slider("PVC_Volume", (Transform)(object)val3, new Vector2(296f, 14f), 0f, 2f, PeerPreferences.GetVolume(_steamId), OnVolumeChanged);
				PinLeft((RectTransform)((Component)_volume).transform, num + 64f + 12f, y, 296f, 14f);
				_volumeText = UIFactory.Text("PVC_VolumeValue", (Transform)(object)val3, "", TextRole.Body, 14, (TextAnchor)3);
				PinLeft((RectTransform)((Component)_volumeText).transform, num + 64f + 12f + 296f + 12f, y, 46f, 20f);
				((Graphic)_volumeText).color = GameColors.Beige;
			}
		}

		private static void GrowRow(RectTransform row)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)((Transform)row).Find("PVC_Tall") != (Object)null))
			{
				GameObject val = new GameObject("PVC_Tall", new Type[1] { typeof(RectTransform) });
				val.transform.SetParent((Transform)(object)row, false);
				val.SetActive(false);
				row.sizeDelta = new Vector2(row.sizeDelta.x, row.sizeDelta.y + 40f);
				LayoutRebuilder.MarkLayoutForRebuild(row);
			}
		}

		private static float NameLeftEdge(RectTransform row)
		{
			//IL_0023: 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_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			RectTransform[] componentsInChildren = ((Component)row).GetComponentsInChildren<RectTransform>(true);
			foreach (RectTransform val in componentsInChildren)
			{
				if (((Object)val).name == "CharacterName" && Mathf.Approximately(val.anchorMin.x, 0f))
				{
					float x = val.anchoredPosition.x;
					float x2 = val.pivot.x;
					Rect rect = val.rect;
					return x - x2 * ((Rect)(ref rect)).width;
				}
			}
			return 76f;
		}

		private static float NameBottomEdge(RectTransform row)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			float num = float.PositiveInfinity;
			RectTransform[] componentsInChildren = ((Component)row).GetComponentsInChildren<RectTransform>(true);
			foreach (RectTransform val in componentsInChildren)
			{
				if (!(((Object)val).name != "CharacterName") || !(((Object)val).name != "Gamertag"))
				{
					float num2 = num;
					float y = val.anchoredPosition.y;
					float num3 = 1f - val.pivot.y;
					Rect rect = val.rect;
					num = Mathf.Min(num2, y - num3 * ((Rect)(ref rect)).height);
				}
			}
			if (!float.IsPositiveInfinity(num))
			{
				return num;
			}
			return -28f;
		}

		private static void Pin(RectTransform rect, float x, float width, float height)
		{
			//IL_000b: 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_0035: 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_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			rect.anchorMin = new Vector2(1f, 0.5f);
			rect.anchorMax = new Vector2(1f, 0.5f);
			rect.pivot = new Vector2(0.5f, 0.5f);
			((Transform)rect).localScale = Vector3.one;
			rect.sizeDelta = new Vector2(width, height);
			rect.anchoredPosition = new Vector2(x, 0f);
		}

		private static void PinLeft(RectTransform rect, float x, float y, float width, float height)
		{
			//IL_000b: 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_0035: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			rect.anchorMin = new Vector2(0f, 0.5f);
			rect.anchorMax = new Vector2(0f, 0.5f);
			rect.pivot = new Vector2(0f, 0.5f);
			((Transform)rect).localScale = Vector3.one;
			rect.sizeDelta = new Vector2(width, height);
			rect.anchoredPosition = new Vector2(x, y);
		}

		private void OnVolumeChanged(float value)
		{
			if (!_suppress)
			{
				PeerPreferences.SetVolume(_steamId, value);
				ProximityVoiceChatPlugin.SaveConfig();
			}
		}

		private void OnClick()
		{
			if (_own)
			{
				ProximityVoiceChatPlugin.MuteSelf.Value = ((!ProximityVoiceChatPlugin.MuteSelf.Value.IsOn()) ? ProximityVoiceChatPlugin.Toggle.On : ProximityVoiceChatPlugin.Toggle.Off);
			}
			else
			{
				PeerPreferences.ToggleMuted(_steamId);
				VoiceRuntime.Instance?.Playback?.Remove(_steamId);
				ProximityVoiceChatPlugin.SaveConfig();
			}
			Refresh();
		}

		private void Update()
		{
			if (!((Object)(object)_icon == (Object)null))
			{
				_timer += Time.unscaledDeltaTime;
				if (!(_timer < 0.1f))
				{
					_timer = 0f;
					Refresh();
				}
			}
		}

		private void Refresh()
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_icon == (Object)null))
			{
				bool flag = (_own ? ProximityVoiceChatPlugin.MuteSelf.Value.IsOn() : PeerPreferences.IsSilenced(_steamId));
				if ((Object)(object)VoiceSprites.Speaker != (Object)null && (Object)(object)VoiceSprites.Muted != (Object)null)
				{
					_icon.sprite = (flag ? VoiceSprites.Muted : VoiceSprites.Speaker);
				}
				((Graphic)_icon).color = (flag ? Blocked : (IsTalking() ? Speaking : Silent));
				RefreshVolume(flag);
			}
		}

		private void RefreshVolume(bool muted)
		{
			if (!((Object)(object)_volume == (Object)null) && !((Object)(object)_volumeText == (Object)null))
			{
				float volume = PeerPreferences.GetVolume(_steamId);
				_suppress = true;
				_volume.SetValueWithoutNotify(volume);
				_suppress = false;
				((Selectable)_volume).interactable = !PeerPreferences.IsBlockedByGame(_steamId);
				_volumeText.text = (muted ? UIBuild.Localize("$pvc_mute") : volume.ToString("0.00"));
			}
		}

		private bool IsTalking()
		{
			VoiceRuntime instance = VoiceRuntime.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			if (_own)
			{
				return instance.Encoder?.IsTransmitting ?? false;
			}
			if (instance.Playback != null && instance.Playback.Streams.TryGetValue(_steamId, out PeerVoiceStream value))
			{
				return value.Speaking;
			}
			return false;
		}
	}
	internal static class VoiceSprites
	{
		private const int Size = 128;

		private const int Samples = 3;

		private const int MaxAlpha = 255;

		private const float PixelsPerUnit = 100f;

		private const int QuietWaves = 1;

		private const int TalkingWaves = 3;

		private const float Middle = 0.5f;

		private const float ConeMouth = 0.5f;

		private const float BodyLeft = 0.16f;

		private const float BodyRight = 0.3f;

		private const float BodyHalfHeight = 0.11f;

		private const float ConeFlare = 0.2f;

		private const float SlashHalfWidth = 0.035f;

		private const float SlashGap = 0.075f;

		private const float WaveArcDegrees = 52f;

		private const float WaveInner = 0.1f;

		private const float WaveSpacing = 0.1f;

		private const float WaveThickness = 0.045f;

		private static readonly Vector2 SlashStart = new Vector2(0.17f, 0.2f);

		private static readonly Vector2 SlashEnd = new Vector2(0.83f, 0.8f);

		private static bool _built;

		internal static Sprite? Speaker { get; private set; }

		internal static Sprite? SpeakerTalking { get; private set; }

		internal static Sprite? Muted { get; private set; }

		internal static void Resolve()
		{
			if (!_built)
			{
				_built = true;
				Speaker = Build(1, slash: false);
				SpeakerTalking = Build(3, slash: false);
				Muted = Build(0, slash: true);
			}
		}

		private static Sprite Build(int waves, bool slash)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//IL_013b: 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_00ef: 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)
			Texture2D val = new Texture2D(128, 128, (TextureFormat)4, false)
			{
				filterMode = (FilterMode)1,
				wrapMode = (TextureWrapMode)1,
				hideFlags = (HideFlags)61
			};
			Color32[] array = (Color32[])(object)new Color32[16384];
			for (int i = 0; i < 128; i++)
			{
				for (int j = 0; j < 128; j++)
				{
					float num = 0f;
					for (int k = 0; k < 3; k++)
					{
						for (int l = 0; l < 3; l++)
						{
							float u = ((float)j + ((float)l + 0.5f) / 3f) / 128f;
							float v = ((float)i + ((float)k + 0.5f) / 3f) / 128f;
							if (Inside(u, v, waves, slash))
							{
								num += 1f;
							}
						}
					}
					num /= 9f;
					byte b = (byte)Mathf.Clamp(Mathf.RoundToInt(num * 255f), 0, 255);
					array[i * 128 + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, b);
				}
			}
			val.SetPixels32(array);
			val.Apply(false, false);
			Sprite obj = Sprite.Create(val, new Rect(0f, 0f, 128f, 128f), new Vector2(0.5f, 0.5f), 100f);
			((Object)obj).hideFlags = (HideFlags)61;
			return obj;
		}

		private static bool Inside(float u, float v, int waves, bool slash)
		{
			if (slash)
			{
				float num = DistanceToSlash(u, v);
				if (num <= 0.035f)
				{
					return true;
				}
				if (num <= 0.075f)
				{
					return false;
				}
			}
			float num2 = Mathf.Abs(v - 0.5f);
			if (u >= 0.16f && u <= 0.3f && num2 <= 0.11f)
			{
				return true;
			}
			if (u > 0.3f && u <= 0.5f && num2 <= 0.11f + (u - 0.3f) / 0.19999999f * 0.2f)
			{
				return true;
			}
			if (waves <= 0)
			{
				return false;
			}
			float num3 = u - 0.5f;
			float num4 = v - 0.5f;
			float num5 = Mathf.Sqrt(num3 * num3 + num4 * num4);
			if (num3 <= 0f)
			{
				return false;
			}
			if (Mathf.Abs(Mathf.Atan2(num4, num3)) * 57.29578f > 52f)
			{
				return false;
			}
			for (int i = 0; i < waves; i++)
			{
				float num6 = 0.1f + (float)i * 0.1f;
				if (num5 >= num6 && num5 <= num6 + 0.045f)
				{
					return true;
				}
			}
			return false;
		}

		private static float DistanceToSlash(float u, float v)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: 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_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: 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_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = new Vector2(u, v);
			Vector2 val2 = SlashEnd - SlashStart;
			float num = Mathf.Clamp01(Vector2.Dot(val - SlashStart, val2) / Vector2.Dot(val2, val2));
			return Vector2.Distance(val, SlashStart + val2 * num);
		}
	}
	internal sealed class SpeakingIndicator : MonoBehaviour
	{
		private sealed class Marker
		{
			internal GameObject Root;

			internal Image Icon;

			internal RectTransform Rect;

			internal float Shown;
		}

		private const float FadeRate = 6f;

		private const float IconSize = 34f;

		private const float PeerHeadHeight = 1.5f;

		private const float FadeBandFraction = 0.25f;

		private const float BounceBase = 0.9f;

		private const float BounceDepth = 0.25f;

		private const float Invisible = 0.001f;

		private static readonly List<RosterEntry> NoPeers = new List<RosterEntry>();

		private readonly List<Marker> _peers = new List<Marker>();

		private Marker? _self;

		private Hud? _hud;

		private void OnDestroy()
		{
			Teardown();
		}

		private void LateUpdate()
		{
			bool flag = ProximityVoiceChatPlugin.ShowSpeakingIndicator.Value.IsOn();
			bool flag2 = ProximityVoiceChatPlugin.PeerIndicators.Value.IsOn();
			if (!flag && !flag2)
			{
				Teardown();
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			Hud instance = Hud.instance;
			Camera mainCamera = Utils.GetMainCamera();
			if ((Object)(object)localPlayer == (Object)null || !Object.op_Implicit((Object)(object)localPlayer) || (Object)(object)instance == (Object)null || !Object.op_Implicit((Object)(object)instance) || (Object)(object)mainCamera == (Object)null || Hud.IsUserHidden())
			{
				HideAll();
				return;
			}
			if ((Object)(object)_hud != (Object)(object)instance)
			{
				Teardown();
				_hud = instance;
			}
			if (flag)
			{
				DrawSelf(instance, mainCamera, localPlayer);
			}
			else
			{
				Fade(_self);
			}
			DrawPeers(instance, mainCamera, flag2);
		}

		private void DrawSelf(Hud hud, Camera camera, Player player)
		{
			//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_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: 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_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			if (_self == null)
			{
				_self = Build(hud, "PVC_Speaking");
			}
			VoiceEncoder voiceEncoder = VoiceRuntime.Instance?.Encoder;
			bool flag = ProximityVoiceChatPlugin.MuteSelf.Value.IsOn() || ProximityVoiceChatPlugin.Deafen.Value.IsOn();
			bool flag2 = !flag && voiceEncoder != null && voiceEncoder.IsSpeaking && VoiceRuntime.GateOpen();
			float level = ((!flag && voiceEncoder != null) ? UIBuild.MeterScale(voiceEncoder.LastRms) : 0f);
			_self.Icon.sprite = (flag ? VoiceSprites.Muted : VoiceSprites.SpeakerTalking);
			Vector3 world = ((Character)player).GetHeadPoint() + Vector3.up * ProximityVoiceChatPlugin.SpeakingIndicatorHeight.Value;
			Place(_self, camera, world, flag2 || flag, flag ? GameColors.Danger : GameColors.Beige, level, 1f, 1f);
		}

		private void DrawPeers(Hud hud, Camera camera, bool wantPeers)
		{
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			VoiceRuntime instance = VoiceRuntime.Instance;
			IReadOnlyList<RosterEntry> readOnlyList;
			if (!((Object)(object)instance != (Object)null && wantPeers))
			{
				IReadOnlyList<RosterEntry> noPeers = NoPeers;
				readOnlyList = noPeers;
			}
			else
			{
				readOnlyList = instance.Roster.Entries;
			}
			IReadOnlyList<RosterEntry> readOnlyList2 = readOnlyList;
			float value = ProximityVoiceChatPlugin.PeerIndicatorScale.Value;
			bool flag = ProximityVoiceChatPlugin.PeerIndicatorThroughWalls.Value.IsOn();
			float value2 = ProximityVoiceChatPlugin.MaxRange.Value;
			while (_peers.Count < readOnlyList2.Count)
			{
				_peers.Add(Build(hud, "PVC_PeerSpeaking"));
			}
			for (int i = 0; i < _peers.Count; i++)
			{
				Marker marker = _peers[i];
				if (i >= readOnlyList2.Count)
				{
					Fade(marker);
					continue;
				}
				RosterEntry rosterEntry = readOnlyList2[i];
				instance.Links.TryGetValue(rosterEntry.SteamId, out PeerLink value3);
				bool flag2 = PeerPreferences.IsSilenced(rosterEntry.SteamId);
				PeerVoiceStream peerVoiceStream = null;
				if (instance.Playback != null && instance.Playback.Streams.TryGetValue(rosterEntry.SteamId, out PeerVoiceStream value4))
				{
					peerVoiceStream = value4;
				}
				bool num = ((!flag2) ? (peerVoiceStream?.Speaking ?? false) : (value3?.Transmitting ?? false));
				bool flag3 = !flag && (peerVoiceStream?.Occluded ?? false);
				bool wanted = num && !flag3 && rosterEntry.HasPosition && (value3?.InRange ?? false);
				marker.Icon.sprite = (flag2 ? VoiceSprites.Muted : VoiceSprites.SpeakerTalking);
				float level = ((!flag2 && peerVoiceStream != null) ? UIBuild.MeterScale(peerVoiceStream.OutputRms) : 0f);
				float num2 = value3?.Distance ?? value2;
				float fade = Mathf.Clamp01((value2 - num2) / Mathf.Max(1f, value2 * 0.25f));
				Vector3 world = HeadOf(rosterEntry) + Vector3.up * ProximityVoiceChatPlugin.PeerIndicatorHeight.Value;
				Place(marker, camera, world, wanted, flag2 ? GameColors.Danger : GameColors.Beige, level, value, fade);
			}
		}

		private static Vector3 HeadOf(RosterEntry entry)
		{
			//IL_001c: 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_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)entry.Player != (Object)null) || !Object.op_Implicit((Object)(object)entry.Player))
			{
				return entry.LastKnownPosition + Vector3.up * 1.5f;
			}
			return ((Character)entry.Player).GetHeadPoint();
		}

		private static void Place(Marker marker, Camera camera, Vector3 world, bool wanted, Color color, float level, float scale, float fade)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: 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_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			marker.Shown = Mathf.MoveTowards(marker.Shown, wanted ? 1f : 0f, 6f * Time.unscaledDeltaTime);
			float num = marker.Shown * fade;
			if (num <= 0.001f)
			{
				Hide(marker);
				return;
			}
			Vector3 val = Utils.WorldToScreenPointScaled(camera, world);
			if (val.z <= 0f)
			{
				Hide(marker);
				return;
			}
			marker.Root.SetActive(true);
			((Transform)marker.Rect).position = val;
			((Transform)marker.Rect).localScale = Vector3.one * scale * (0.9f + 0.25f * level) * marker.Shown;
			color.a = num;
			((Graphic)marker.Icon).color = color;
		}

		private static Marker Build(Hud hud, string name)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			VoiceSprites.Resolve();
			GameObject val = new GameObject(name, new Type[3]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image)
			});
			val.transform.SetParent(((Component)hud).transform, false);
			RectTransform val2 = (RectTransform)val.transform;
			val2.sizeDelta = new Vector2(34f, 34f);
			Image component = val.GetComponent<Image>();
			component.sprite = VoiceSprites.SpeakerTalking;
			((Graphic)component).raycastTarget = false;
			component.preserveAspect = true;
			val.SetActive(false);
			return new Marker
			{
				Root = val,
				Icon = component,
				Rect = val2
			};
		}

		private static void Fade(Marker? marker)
		{
			if (marker != null)
			{
				marker.Shown = Mathf.MoveTowards(marker.Shown, 0f, 6f * Time.unscaledDeltaTime);
				if (marker.Shown <= 0.001f)
				{
					Hide(marker);
				}
			}
		}

		private static void Hide(Marker marker)
		{
			if ((Object)(object)marker.Root != (Object)null && marker.Root.activeSelf)
			{
				marker.Root.SetActive(false);
			}
		}

		private void HideAll()
		{
			if (_self != null)
			{
				Hide(_self);
			}
			for (int i = 0; i < _peers.Count; i++)
			{
				Hide(_peers[i]);
			}
		}

		private void Teardown()
		{
			if (_self != null)
			{
				Object.Destroy((Object)(object)_self.Root);
				_self = null;
			}
			for (int i = 0; i < _peers.Count; i++)
			{
				Object.Destroy((Object)(object)_peers[i].Root);
			}
			_peers.Clear();
			_hud = null;
		}
	}
	internal static class KeyBinder
	{
		private static readonly KeyCode[] Modifiers;

		private static KeyCode[]? _candidates;

		private static int _startedFrame;

		private static readonly List<KeyCode> Held;

		internal static ConfigEntry<KeyboardShortcut>? Target;

		internal static bool Listening => Target != null;

		internal static bool IsListening(ConfigEntry<KeyboardShortcut> entry)
		{
			return Target == entry;
		}

		internal static void Begin(ConfigEntry<KeyboardShortcut> entry)
		{
			Target = entry;
			_startedFrame = Time.frameCount;
		}

		internal static void Cancel()
		{
			Target = null;
		}

		internal static void Tick()
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: 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_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Invalid comparison between I4 and Unknown
			//IL_00c2: 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)
			ConfigEntry<KeyboardShortcut> target = Target;
			if (target == null || !Input.anyKeyDown || Time.frameCount == _startedFrame)
			{
				return;
			}
			if (Input.GetKeyDown((KeyCode)27))
			{
				Target = null;
				return;
			}
			if (Input.GetKeyDown((KeyCode)8) || Input.GetKeyDown((KeyCode)127))
			{
				target.Value = new KeyboardShortcut((KeyCode)0, Array.Empty<KeyCode>());
				Target = null;
				return;
			}
			if (_candidates == null)
			{
				_candidates = BuildCandidates();
			}
			for (int i = 0; i < _candidates.Length; i++)
			{
				KeyCode val = _candidates[i];
				if (!Input.GetKeyDown(val))
				{
					continue;
				}
				Held.Clear();
				for (int j = 0; j < Modifiers.Length; j++)
				{
					if ((int)Modifiers[j] != (int)val && Input.GetKey(Modifiers[j]))
					{
						Held.Add(Modifiers[j]);
					}
				}
				target.Value = new KeyboardShortcut(val, Held.ToArray());
				Target = null;
				break;
			}
		}

		internal static string Describe(KeyboardShortcut shortcut)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey == 0)
			{
				return UIBuild.Localize("$pvc_key_unbound");
			}
			string text = "";
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers)
			{
				text = text + ((object)modifier/*cast due to .constrained prefix*/).ToString() + " + ";
			}
			return text + ((object)((KeyboardShortcut)(ref shortcut)).MainKey/*cast due to .constrained prefix*/).ToString();
		}

		private static KeyCode[] BuildCandidates()
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: 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_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Invalid comparison between Unknown and I4
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			List<KeyCode> list = new List<KeyCode>();
			foreach (KeyCode value in Enum.GetValues(typeof(KeyCode)))
			{
				if ((int)value != 0 && (int)value != 323 && !((object)value/*cast due to .constrained prefix*/).ToString().StartsWith("Joystick", StringComparison.Ordinal))
				{
					list.Add(value);
				}
			}
			return list.ToArray();
		}

		static KeyBinder()
		{
			KeyCode[] array = new KeyCode[6];
			RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
			Modifiers = (KeyCode[])(object)array;
			Held = new List<KeyCode>();
		}
	}
}
namespace ProximityVoiceChat.Voice
{
	internal static class MusicDucking
	{
		[HarmonyPatch(typeof(MusicMan), "UpdateMusic")]
		private static class MusicMan_UpdateMusic_Patch
		{
			private static void Postfix(MusicMan __instance)
			{
				if (!(_duck >= 0.999f) && !((Object)(object)__instance.m_musicSource == (Object)null))
				{
					AudioSource musicSource = __instance.m_musicSource;
					musicSource.volume *= _duck;
				}
			}
		}

		private const float FadeRate = 3f;

		private static float _duck = 1f;

		internal static void Tick(float deltaTime, bool someoneSpeaking)
		{
			float num = 1f;
			if (someoneSpeaking && ProximityVoiceChatPlugin.DuckMusic.Value.IsOn())
			{
				num = Mathf.Clamp01(ProximityVoiceChatPlugin.DuckMusicAmount.Value);
			}
			_duck = Mathf.MoveTowards(_duck, num, 3f * deltaTime);
		}

		internal static void Reset()
		{
			_duck = 1f;
		}
	}
	internal sealed class JawAnimator : MonoBehaviour
	{
		private sealed class Mouth
		{
			internal Transform? Jaw;

			internal Quaternion Rest;

			internal float Open;

			internal float Seed;

			internal bool Missing;
		}

		private const string JawBone = "Jaw";

		private const float AttackPerSecond = 14f;

		private const float ReleasePerSecond = 7f;

		private const float Floor = 0.012f;

		private const float Closed = 0.0005f;

		private const float WobbleBase = 0.85f;

		private const float WobbleDepth = 0.15f;

		private const float WobbleHz = 9f;

		private const float SeedRange = 10f;

		private readonly Dictionary<Player, Mouth> _mouths = new Dictionary<Player, Mouth>();

		private readonly List<Player> _stale = new List<Player>();

		private void LateUpdate()
		{
			if (ProximityVoiceChatPlugin.JawMovement.Value == ProximityVoiceChatPlugin.Toggle.Off || (Object)(object)ZNet.instance == (Object)null)
			{
				if (_mouths.Count > 0)
				{
					ReleaseAll();
				}
				return;
			}
			VoiceRuntime instance = VoiceRuntime.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			float deltaTime = Time.deltaTime;
			VoiceEncoder encoder = instance.Encoder;
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null && Object.op_Implicit((Object)(object)localPlayer))
			{
				float level = ((encoder != null && encoder.IsSpeaking && VoiceRuntime.GateOpen()) ? encoder.LastRms : 0f);
				if (ProximityVoiceChatPlugin.LoopbackTest.Value.IsOn() && instance.Playback != null && instance.Playback.Streams.TryGetValue(1uL, out PeerVoiceStream value))
				{
					level = (value.Speaking ? value.OutputRms : 0f);
				}
				Drive(localPlayer, level, deltaTime);
			}
			if (instance.Playback != null)
			{
				IReadOnlyList<RosterEntry> entries = instance.Roster.Entries;
				for (int i = 0; i < entries.Count; i++)
				{
					RosterEntry rosterEntry = entries[i];
					if (!((Object)(object)rosterEntry.Player == (Object)null) && Object.op_Implicit((Object)(object)rosterEntry.Player))
					{
						PeerVoiceStream value2;
						float level2 = ((instance.Playback.Streams.TryGetValue(rosterEntry.SteamId, out value2)