Decompiled source of Big Voice v1.0.2

BigVoice.dll

Decompiled 3 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using BigVoice.Configuration;
using Dissonance.Audio.Playback;
using HarmonyLib;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Microsoft.CodeAnalysis;
using Mirror;
using Rewired;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("BigVoice")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+4e2352a9dc4752c0718672eb17293ce5cb0b7461")]
[assembly: AssemblyProduct("Big Voice")]
[assembly: AssemblyTitle("BigVoice")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BigVoice
{
	[BepInPlugin("BigVoice", "Big Voice", "1.0.0")]
	public class Plugin : BasePlugin
	{
		internal static Plugin Instance;

		internal static ManualLogSource Log;

		internal static ConfigFile PluginConfig;

		internal static ConfigEntry<float> UnknownPlayerVolume;

		private Harmony _harmony;

		private GameObject _configurationUiObject;

		public ConfigurationHandler ConfigurationHandler { get; private set; }

		public override void Load()
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			Instance = this;
			Log = ((BasePlugin)this).Log;
			PluginConfig = ((BasePlugin)this).Config;
			UnknownPlayerVolume = ((BasePlugin)this).Config.Bind<float>("General", "UnknownPlayerVolume", 1f, new ConfigDescription("VOIP multiplier for players without a matching entry. 0 = muted, 1 = normal, 15 = max.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 15f), Array.Empty<object>()));
			ConfigurationHandler = new ConfigurationHandler(((BasePlugin)this).Config);
			_harmony = new Harmony("BigVoice");
			HarmonyPatches();
			CreateConfigurationUI();
			Log.LogInfo((object)"Big Voice loaded");
		}

		private void CreateConfigurationUI()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected O, but got Unknown
			try
			{
				ClassInjector.RegisterTypeInIl2Cpp<ModConfigurationUI>();
			}
			catch (Exception ex)
			{
				Log.LogDebug((object)("ModConfigurationUI type registration skipped or failed: " + ex.Message));
			}
			_configurationUiObject = new GameObject("Big Voice Configuration UI");
			Object.DontDestroyOnLoad((Object)(object)_configurationUiObject);
			((Object)_configurationUiObject).hideFlags = (HideFlags)61;
			_configurationUiObject.AddComponent<ModConfigurationUI>().Init();
		}

		private void HarmonyPatches()
		{
			TryPatch(AccessTools.Method(typeof(PlayerNetworking), "OnStartClient", Type.EmptyTypes, (Type[])null), null, AccessTools.Method(typeof(PlayerNetworkingPatch), "RegisterPostfix", (Type[])null, (Type[])null), "PlayerNetworking.OnStartClient");
			TryPatch(AccessTools.Method(typeof(PlayerNetworking), "Start", Type.EmptyTypes, (Type[])null), null, AccessTools.Method(typeof(PlayerNetworkingPatch), "RegisterPostfix", (Type[])null, (Type[])null), "PlayerNetworking.Start");
			TryPatch(AccessTools.Method(typeof(PlayerVoicePlaybackControl), "Update", Type.EmptyTypes, (Type[])null), null, AccessTools.Method(typeof(PlayerVoicePlaybackControlPatch), "UpdatePostfix", (Type[])null, (Type[])null), "PlayerVoicePlaybackControl.Update");
			TryPatch(AccessTools.Method(typeof(SamplePlaybackComponent), "ProcessSamples", (Type[])null, (Type[])null), null, AccessTools.Method(typeof(SamplePlaybackComponentPatch), "ProcessSamplesPostfix", (Type[])null, (Type[])null), "SamplePlaybackComponent.ProcessSamples");
		}

		private void TryPatch(MethodInfo original, MethodInfo prefix, MethodInfo postfix, string patchName)
		{
			//IL_0032: 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)
			if (original == null)
			{
				Log.LogError((object)("Failed to find patch target: " + patchName));
				return;
			}
			try
			{
				_harmony.Patch((MethodBase)original, (prefix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(prefix), (postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(postfix), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Patches patchInfo = Harmony.GetPatchInfo((MethodBase)original);
				int valueOrDefault = (patchInfo?.Prefixes?.Count).GetValueOrDefault();
				int valueOrDefault2 = (patchInfo?.Postfixes?.Count).GetValueOrDefault();
				Log.LogInfo((object)("Installed patch for " + patchName + " prefixes=" + valueOrDefault + " postfixes=" + valueOrDefault2));
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Failed to apply the patch for " + patchName + ": " + ex));
			}
		}
	}
	internal static class PlayerNetworkingPatch
	{
		public static void RegisterPostfix(PlayerNetworking __instance)
		{
			PlayerVolumeConfig.Register(__instance);
		}
	}
	internal static class PlayerVoicePlaybackControlPatch
	{
		public static void UpdatePostfix(PlayerVoicePlaybackControl __instance)
		{
			PlayerCharacter val = ((__instance != null) ? __instance.playerCharacter : null);
			if ((Object)(object)((val != null) ? val.playerNetworking : null) != (Object)null)
			{
				PlayerVolumeConfig.Register(val.playerNetworking);
				if ((Object)(object)__instance.dissonanceSampleProvider != (Object)null)
				{
					PlayerVolumeConfig.RegisterSampleProvider(__instance.dissonanceSampleProvider, val.playerNetworking);
				}
			}
		}
	}
	internal static class SamplePlaybackComponentPatch
	{
		public static void ProcessSamplesPostfix(SamplePlaybackComponent __instance, ref Il2CppStructArray<float> data, int channels)
		{
			float volume = PlayerVolumeConfig.GetVolume(__instance);
			ApplyGain(data, volume);
		}

		private static void ApplyGain(Il2CppStructArray<float> data, float volume)
		{
			if (data != null && !Mathf.Approximately(volume, 1f))
			{
				for (int i = 0; i < ((Il2CppArrayBase<float>)(object)data).Length; i++)
				{
					int num = i;
					((Il2CppArrayBase<float>)(object)data)[num] = ((Il2CppArrayBase<float>)(object)data)[num] * volume;
				}
			}
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "BigVoice";

		public const string PLUGIN_NAME = "Big Voice";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}
namespace BigVoice.Configuration
{
	public class ConfigurationHandler
	{
		private sealed class ConfigChangeListener<T>
		{
			private readonly ConfigEntry<T> _entry;

			private readonly Action _onChanged;

			private readonly Func<T, T> _clamp;

			public ConfigChangeListener(ConfigEntry<T> entry, Action onChanged, Func<T, T> clamp)
			{
				_entry = entry;
				_onChanged = onChanged;
				_clamp = clamp;
			}

			public void OnSettingChanged(object sender, EventArgs args)
			{
				if (_clamp != null)
				{
					_entry.Value = _clamp(_entry.Value);
				}
				_onChanged();
			}
		}

		private readonly ConfigFile _config;

		public KeyCode MenuKey { get; private set; }

		public ConfigEntry<string> ConfigMenuKey { get; }

		public ConfigEntry<float> ConfigUnknownPlayerVolume => Plugin.UnknownPlayerVolume;

		public ConfigurationHandler(ConfigFile configFile)
		{
			_config = configFile;
			Plugin.Log.LogInfo((object)"ConfigurationHandler initialising");
			ConfigMenuKey = Bind("General", "Config Menu Key", "F10", "Keyboard key for opening the Big Voice configuration menu", SetupInputKey);
			SetupInputKey();
			Plugin.Log.LogInfo((object)"ConfigurationHandler initialised");
		}

		private ConfigEntry<T> Bind<T>(string section, string key, T defaultValue, string description, Action onChanged = null, Func<T, T> clamp = null)
		{
			ConfigEntry<T> val = _config.Bind<T>(section, key, defaultValue, description);
			if (clamp != null)
			{
				val.Value = clamp(val.Value);
			}
			Plugin.Log.LogInfo((object)(key + " set to " + val.Value));
			if (onChanged != null)
			{
				AddSettingChangedHandler(val, onChanged, clamp);
			}
			return val;
		}

		private static void AddSettingChangedHandler<T>(ConfigEntry<T> entry, Action onChanged, Func<T, T> clamp)
		{
			EventInfo eventInfo = typeof(ConfigEntry<T>).GetEvent("SettingChanged");
			if (eventInfo == null)
			{
				Plugin.Log.LogWarning((object)("Could not subscribe to SettingChanged for " + ((ConfigEntryBase)entry).Definition.Key));
				return;
			}
			ConfigChangeListener<T> firstArgument = new ConfigChangeListener<T>(entry, onChanged, clamp);
			MethodInfo method = typeof(ConfigChangeListener<T>).GetMethod("OnSettingChanged", BindingFlags.Instance | BindingFlags.Public);
			Delegate handler = Delegate.CreateDelegate(eventInfo.EventHandlerType, firstArgument, method);
			eventInfo.AddEventHandler(entry, handler);
		}

		private void SetupInputKey()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if (Enum.TryParse<KeyCode>(ConfigMenuKey.Value, out KeyCode result))
			{
				MenuKey = result;
				Plugin.Log.LogInfo((object)("Menu key set to " + ((object)MenuKey/*cast due to .constrained prefix*/).ToString()));
			}
			else
			{
				MenuKey = (KeyCode)291;
				Plugin.Log.LogWarning((object)("Invalid menu key " + ConfigMenuKey.Value + ", using F10"));
			}
		}
	}
	public class ModConfigurationUI : MonoBehaviour
	{
		private const int MouseWheelAxis = 2;

		private List<Option> _options = new List<Option>();

		private bool _visible;

		private int _selectedIndex;

		private int _scrollStartIndex;

		private int _knownPlayerConfigVersion = -1;

		private bool _prevCursorVisible;

		private CursorLockMode _prevCursorLock;

		private bool _waitingForBinding;

		private Option _bindingTarget;

		private Texture2D _whiteTex;

		private GUIStyle _titleStyle;

		private GUIStyle _rowStyle;

		private GUIStyle _hintStyle;

		private string titleText = "Big Voice | v 1.0.0";

		private string hintText = "F11: Open/Close | Tab or Up/Down: Move | Enter/Click: Change | Scroll Wheel or Left/Right: Adjust Volume | +/-: Scale Menu";

		private int RowHeight = 32;

		private int PanelWidth = 460;

		private int Pad = 12;

		private int TitleFontSize = 22;

		private int OptionFontSize = 16;

		private int HintFontSize = 14;

		private Player _player;

		private Keyboard _keyboard;

		private Mouse _mouse;

		public ModConfigurationUI(IntPtr ptr)
			: base(ptr)
		{
		}

		private Color GetColor(Color c)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			//IL_0011: 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)SystemInfo.graphicsDeviceType == 21)
			{
				return ((Color)(ref c)).linear;
			}
			return c;
		}

		private void CalculatePanelWidth()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected O, but got Unknown
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			float num = _titleStyle.CalcSize(new GUIContent(titleText)).x;
			foreach (Option option in _options)
			{
				float x = _rowStyle.CalcSize(new GUIContent(option.Label + ": " + option.DisplayValue())).x;
				if (x > num)
				{
					num = x;
				}
			}
			int num2 = CalculateHintWidth();
			num = Mathf.Max(num, (float)num2);
			PanelWidth = Mathf.Clamp((int)num + Pad * 2, 460, Screen.width - Pad * 2);
		}

		private int CalculateHintWidth()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			float num = _hintStyle.CalcHeight(new GUIContent("Test"), 9999f) * 2f;
			for (int i = 200; i < Screen.width - Pad * 2; i += 20)
			{
				if (_hintStyle.CalcHeight(new GUIContent(hintText), (float)i) <= num)
				{
					return i;
				}
			}
			return Screen.width - Pad * 2;
		}

		private void Scale(int scale)
		{
			if (scale >= 0 || HintFontSize >= 2)
			{
				TitleFontSize += scale * 2;
				OptionFontSize += scale * 2;
				HintFontSize += scale * 2;
				RowHeight = OptionFontSize + 16;
				CalculatePanelWidth();
			}
		}

		public void Init()
		{
			RebuildOptions();
			_selectedIndex = 0;
			UpdateHintText();
		}

		private void RebuildOptionsIfNeeded()
		{
			if (_knownPlayerConfigVersion != PlayerVolumeConfig.Version)
			{
				RebuildOptions();
			}
		}

		private void RebuildOptions()
		{
			ConfigurationHandler configurationHandler = Plugin.Instance.ConfigurationHandler;
			string selectedLabel = ((_options.Count > 0 && _selectedIndex >= 0 && _selectedIndex < _options.Count) ? _options[_selectedIndex].Label : null);
			List<Option> list = new List<Option> { Option.Float("Default Player Volume", configurationHandler.ConfigUnknownPlayerVolume, 0f, 15f, 0.25f) };
			foreach (PlayerVolumeOption playerOption in PlayerVolumeConfig.GetPlayerOptions())
			{
				list.Add(Option.Float(playerOption.DisplayName, playerOption.ConfigEntry, 0f, 15f, 0.25f));
			}
			list.Add(Option.InputAction("Menu Key", configurationHandler.ConfigMenuKey));
			_options = list;
			_knownPlayerConfigVersion = PlayerVolumeConfig.Version;
			if (selectedLabel != null)
			{
				int num = _options.FindIndex((Option option) => option.Label == selectedLabel);
				_selectedIndex = ((num >= 0) ? num : Mathf.Clamp(_selectedIndex, 0, _options.Count - 1));
			}
			else
			{
				_selectedIndex = Mathf.Clamp(_selectedIndex, 0, _options.Count - 1);
			}
			UpdateHintText();
		}

		private void UpdateHintText()
		{
			string text = Plugin.Instance.ConfigurationHandler.ConfigMenuKey.Value.Split("/")[^1].ToUpper();
			hintText = text + ": Open/Close | Tab or Up/Down: Move | Enter/Click: Change | Scroll Wheel or Left/Right: Adjust Volume | +/-: Scale Menu";
		}

		private void EnsureStyles()
		{
			//IL_004b: 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_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			//IL_00a8: Expected O, but got Unknown
			//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_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Expected O, but got Unknown
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_whiteTex == (Object)null)
			{
				_whiteTex = new Texture2D(1, 1, (TextureFormat)4, false);
				_whiteTex.SetPixel(0, 0, GetColor(Color.white));
				_whiteTex.Apply();
			}
			_titleStyle = new GUIStyle(GUI.skin.label)
			{
				fontSize = TitleFontSize,
				alignment = (TextAnchor)3,
				fontStyle = (FontStyle)1
			};
			_rowStyle = new GUIStyle(GUI.skin.button)
			{
				alignment = (TextAnchor)3,
				fontSize = OptionFontSize,
				padding = new RectOffset(10, 10, 4, 4)
			};
			_hintStyle = new GUIStyle(GUI.skin.label)
			{
				fontSize = HintFontSize,
				alignment = (TextAnchor)3,
				wordWrap = true
			};
		}

		private void Update()
		{
			//IL_0138: 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_0071: 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_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Expected O, but got Unknown
			if (!ReInput.isReady)
			{
				return;
			}
			if (_player == null)
			{
				_player = ReInput.players.GetPlayer(0);
				_keyboard = ReInput.controllers.Keyboard;
				_mouse = ReInput.controllers.Mouse;
			}
			if (_waitingForBinding)
			{
				bool flag = default(bool);
				foreach (KeyCode value in Enum.GetValues(typeof(KeyCode)))
				{
					if (_keyboard.GetKeyDown(value))
					{
						string text = ((object)value/*cast due to .constrained prefix*/).ToString();
						_bindingTarget.StringEntry.Value = text;
						ManualLogSource log = Plugin.Log;
						BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(12, 2, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Rebound ");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(_bindingTarget.Label);
							((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" to ");
							((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(text);
						}
						log.LogInfo(val2);
						_waitingForBinding = false;
						UpdateHintText();
						_bindingTarget = null;
						break;
					}
				}
				return;
			}
			if (_keyboard.GetKeyDown(Plugin.Instance.ConfigurationHandler.MenuKey))
			{
				_visible = !_visible;
				if (_visible)
				{
					OnOpened();
				}
				else
				{
					OnClosed();
				}
			}
			if (_visible && _options.Count != 0)
			{
				RebuildOptionsIfNeeded();
				if (_keyboard.GetKeyDown((KeyCode)9))
				{
					bool flag2 = _keyboard.GetKey((KeyCode)304) || _keyboard.GetKey((KeyCode)303);
					CycleSelection((!flag2) ? 1 : (-1));
				}
				if (_keyboard.GetKeyDown((KeyCode)61) || _keyboard.GetKeyDown((KeyCode)43))
				{
					Scale(1);
				}
				if (_keyboard.GetKeyDown((KeyCode)45))
				{
					Scale(-1);
				}
				if (_keyboard.GetKeyDown((KeyCode)273))
				{
					CycleSelection(-1);
				}
				if (_keyboard.GetKeyDown((KeyCode)274))
				{
					CycleSelection(1);
				}
				if (_keyboard.GetKeyDown((KeyCode)13) || _keyboard.GetKeyDown((KeyCode)271))
				{
					ToggleSelected();
				}
				if (_keyboard.GetKeyDown((KeyCode)276))
				{
					AdjustNumerical(-1);
				}
				if (_keyboard.GetKeyDown((KeyCode)275))
				{
					AdjustNumerical(1);
				}
				float axis = ((ControllerWithAxes)_mouse).GetAxis(2);
				if (axis > 0f)
				{
					AdjustNumerical(1);
				}
				else if (axis < 0f)
				{
					AdjustNumerical(-1);
				}
			}
		}

		private void ToggleSelected()
		{
			Option option = _options[_selectedIndex];
			if (option.IsDisabled())
			{
				return;
			}
			switch (option.Type)
			{
			case Option.OptionType.Bool:
				option.BoolEntry.Value = !option.BoolEntry.Value;
				break;
			case Option.OptionType.Int:
			{
				int num2 = option.IntEntry.Value + option.Step;
				if (num2 > option.MaxInt)
				{
					num2 = option.MinInt;
				}
				option.IntEntry.Value = num2;
				break;
			}
			case Option.OptionType.Float:
			{
				float num = option.FloatEntry.Value + option.FloatStep;
				if (num > option.MaxFloat)
				{
					num = option.MinFloat;
				}
				option.FloatEntry.Value = num;
				break;
			}
			case Option.OptionType.InputAction:
				_waitingForBinding = true;
				_bindingTarget = option;
				break;
			case Option.OptionType.String:
				break;
			}
		}

		private void AdjustNumerical(int delta)
		{
			Option option = _options[_selectedIndex];
			if (!option.IsDisabled())
			{
				if (option.Type == Option.OptionType.Bool)
				{
					option.BoolEntry.Value = delta > 0;
				}
				else if (option.Type == Option.OptionType.Int)
				{
					AdjustInt(option, delta);
				}
				else if (option.Type == Option.OptionType.Float)
				{
					AdjustFloat(option, delta);
				}
			}
		}

		private static void AdjustInt(Option option, int delta)
		{
			int value = option.IntEntry.Value;
			int num = value;
			int num2 = Mathf.Max(1, Mathf.CeilToInt((float)(option.MaxInt - option.MinInt) / (float)option.Step) + 1);
			for (int i = 0; i < num2; i++)
			{
				int num3 = Mathf.Clamp(num + delta * option.Step, option.MinInt, option.MaxInt);
				if (num3 == num)
				{
					break;
				}
				option.IntEntry.Value = num3;
				if (option.IntEntry.Value != value)
				{
					break;
				}
				num = num3;
			}
		}

		private static void AdjustFloat(Option option, int delta)
		{
			float value = option.FloatEntry.Value;
			float num = value;
			int num2 = Mathf.Max(1, Mathf.CeilToInt((option.MaxFloat - option.MinFloat) / option.FloatStep) + 1);
			for (int i = 0; i < num2; i++)
			{
				float num3 = Mathf.Clamp(num + (float)delta * option.FloatStep, option.MinFloat, option.MaxFloat);
				if (Mathf.Approximately(num3, num))
				{
					break;
				}
				option.FloatEntry.Value = num3;
				if (!Mathf.Approximately(option.FloatEntry.Value, value))
				{
					break;
				}
				num = num3;
			}
		}

		private void OnOpened()
		{
			//IL_0012: 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)
			RebuildOptionsIfNeeded();
			_prevCursorVisible = Cursor.visible;
			_prevCursorLock = Cursor.lockState;
			Cursor.visible = true;
			Cursor.lockState = (CursorLockMode)0;
			if (_options.Count > 0 && _options[_selectedIndex].IsDisabled())
			{
				CycleSelection(1);
			}
		}

		private void OnClosed()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			Cursor.visible = _prevCursorVisible;
			Cursor.lockState = _prevCursorLock;
		}

		private void CycleSelection(int delta)
		{
			if (_options.Count == 0)
			{
				return;
			}
			int selectedIndex = _selectedIndex;
			do
			{
				_selectedIndex = (_selectedIndex + delta) % _options.Count;
				if (_selectedIndex < 0)
				{
					_selectedIndex += _options.Count;
				}
			}
			while (_options[_selectedIndex].IsDisabled() && _selectedIndex != selectedIndex);
		}

		private void EnsureSelectedVisible(int visibleRows)
		{
			if (visibleRows <= 0)
			{
				_scrollStartIndex = 0;
				return;
			}
			if (_selectedIndex < _scrollStartIndex)
			{
				_scrollStartIndex = _selectedIndex;
			}
			else if (_selectedIndex >= _scrollStartIndex + visibleRows)
			{
				_scrollStartIndex = _selectedIndex - visibleRows + 1;
			}
			_scrollStartIndex = Mathf.Clamp(_scrollStartIndex, 0, Mathf.Max(0, _options.Count - visibleRows));
		}

		private void OnGUI()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Expected O, but got Unknown
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0388: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02de: Unknown result type (might be due to invalid IL or missing references)
			if (!_visible)
			{
				return;
			}
			RebuildOptionsIfNeeded();
			EnsureStyles();
			CalculatePanelWidth();
			float num = _titleStyle.CalcHeight(new GUIContent(titleText), (float)(PanelWidth - Pad * 2));
			float num2 = _options.Count * (RowHeight + 4);
			float num3 = _hintStyle.CalcHeight(new GUIContent("Test"), 9999f) * 2f;
			int num4 = Mathf.Max(1, Mathf.Min(_options.Count, Mathf.FloorToInt(((float)(Screen.height - 80) - num - num3 - (float)(Pad * 3)) / (float)(RowHeight + 4))));
			EnsureSelectedVisible(num4);
			num2 = num4 * (RowHeight + 4);
			int num5 = Pad + (int)num + 8 + (int)num2 + Pad + (int)num3;
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(20f, 20f, (float)PanelWidth, (float)num5);
			GUI.color = GetColor(new Color(0f, 0f, 0f, 0.75f));
			GUI.DrawTexture(val, (Texture)(object)_whiteTex);
			GUI.color = Color.white;
			Rect val2 = default(Rect);
			((Rect)(ref val2))..ctor(((Rect)(ref val)).x + (float)Pad, ((Rect)(ref val)).y + (float)Pad, ((Rect)(ref val)).width - (float)(Pad * 2), num);
			GUI.Label(val2, titleText, _titleStyle);
			float num6 = ((Rect)(ref val2)).yMax + 8f;
			int num7 = Mathf.Min(_options.Count, _scrollStartIndex + num4);
			Rect val3 = default(Rect);
			for (int i = _scrollStartIndex; i < num7; i++)
			{
				((Rect)(ref val3))..ctor(((Rect)(ref val)).x + (float)Pad, num6, ((Rect)(ref val)).width - (float)(Pad * 2), (float)RowHeight);
				Option option = _options[i];
				if (((Rect)(ref val3)).Contains(Event.current.mousePosition) && !option.IsDisabled())
				{
					_selectedIndex = i;
				}
				if (i == _selectedIndex && !option.IsDisabled())
				{
					GUI.color = GetColor(new Color(1f, 1f, 1f, 0.24f));
					GUI.DrawTexture(val3, (Texture)(object)_whiteTex);
					GUI.color = Color.white;
				}
				GUI.enabled = !option.IsDisabled();
				if (option.Label == "Menu Key" && _waitingForBinding)
				{
					GUI.color = GetColor(new Color(0f, 0f, 0f, 0.6f));
					GUI.DrawTexture(val3, (Texture)(object)_whiteTex);
					GUI.color = Color.white;
					GUI.Button(val3, "Press any key...", _rowStyle);
				}
				else if (GUI.Button(val3, option.Label + ": " + option.DisplayValue(), _rowStyle) && !option.IsDisabled())
				{
					ToggleSelected();
				}
				GUI.enabled = true;
				num6 += (float)(RowHeight + 4);
			}
			GUI.Label(new Rect(((Rect)(ref val)).x + (float)Pad, ((Rect)(ref val)).yMax - (float)Pad - num3, ((Rect)(ref val)).width - (float)(Pad * 2), num3), hintText, _hintStyle);
		}

		private void OnDestroy()
		{
			if ((Object)(object)_whiteTex != (Object)null)
			{
				Object.Destroy((Object)(object)_whiteTex);
				_whiteTex = null;
			}
		}
	}
	public class Option
	{
		public enum OptionType
		{
			Bool,
			Int,
			String,
			InputAction,
			Float
		}

		public string Label { get; set; }

		public OptionType Type { get; set; }

		public ConfigEntry<bool> BoolEntry { get; set; }

		public ConfigEntry<int> IntEntry { get; set; }

		public ConfigEntry<string> StringEntry { get; set; }

		public int MinInt { get; set; }

		public int MaxInt { get; set; }

		public int Step { get; set; }

		public Func<bool> IsDisabled { get; set; } = () => false;

		public Func<string> DisplayValue { get; set; } = () => "";

		public ConfigEntry<float> FloatEntry { get; set; }

		public float MinFloat { get; set; }

		public float MaxFloat { get; set; }

		public float FloatStep { get; set; }

		private Option(string label, OptionType type)
		{
			Label = label;
			Type = type;
		}

		public static Option Float(string label, ConfigEntry<float> entry, float min, float max, float step = 0.05f, Func<bool> isDisabled = null, Func<string> displayValue = null)
		{
			return new Option(label, OptionType.Float)
			{
				FloatEntry = entry,
				MinFloat = min,
				MaxFloat = max,
				FloatStep = step,
				IsDisabled = (isDisabled ?? ((Func<bool>)(() => false))),
				DisplayValue = (displayValue ?? ((Func<string>)(() => entry.Value.ToString("F2") + "x")))
			};
		}

		public static Option Bool(string label, ConfigEntry<bool> entry, Func<bool> isDisabled = null)
		{
			return new Option(label, OptionType.Bool)
			{
				BoolEntry = entry,
				IsDisabled = (isDisabled ?? ((Func<bool>)(() => false))),
				DisplayValue = () => (!entry.Value) ? "OFF" : "ON"
			};
		}

		public static Option InputAction(string label, ConfigEntry<string> entry, Func<bool> isDisabled = null)
		{
			return new Option(label, OptionType.InputAction)
			{
				StringEntry = entry,
				IsDisabled = (isDisabled ?? ((Func<bool>)(() => false))),
				DisplayValue = delegate
				{
					string[] array = entry.Value.Split("/");
					return (array.Length <= 1) ? entry.Value : array[^1].ToUpper();
				}
			};
		}

		public static Option Int(string label, ConfigEntry<int> entry, int min, int max, int step = 1, Func<bool> isDisabled = null, Func<string> displayValue = null)
		{
			return new Option(label, OptionType.Int)
			{
				IntEntry = entry,
				MinInt = min,
				MaxInt = max,
				Step = step,
				IsDisabled = (isDisabled ?? ((Func<bool>)(() => false))),
				DisplayValue = (displayValue ?? ((Func<string>)(() => entry.Value.ToString())))
			};
		}
	}
	internal sealed class PlayerRecord(string displayName, ConfigEntry<float> configEntry)
	{
		public string DisplayName { get; set; } = displayName;

		public ConfigEntry<float> ConfigEntry { get; } = configEntry;
	}
	internal static class PlayerVolumeConfig
	{
		private const string PlayerVolumesSection = "Player Volumes";

		public const float MinVolume = 0f;

		public const float MaxVolume = 15f;

		public const float VolumeStep = 0.25f;

		private static readonly List<PlayerRecord> Records = new List<PlayerRecord>();

		private static readonly Dictionary<string, PlayerRecord> RecordsById = new Dictionary<string, PlayerRecord>();

		private static readonly Dictionary<int, PlayerRecord> RecordsBySampleProviderId = new Dictionary<int, PlayerRecord>();

		public static int Version { get; private set; }

		public static void Register(PlayerNetworking networking)
		{
			try
			{
				GetOrCreateRecord(networking);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogDebug((object)("Failed to register player VOIP volume: " + ex));
			}
		}

		public static void RegisterSampleProvider(SamplePlaybackComponent sampleProvider, PlayerNetworking networking)
		{
			if ((Object)(object)sampleProvider == (Object)null)
			{
				return;
			}
			try
			{
				PlayerRecord orCreateRecord = GetOrCreateRecord(networking);
				if (orCreateRecord != null)
				{
					RecordsBySampleProviderId[((Object)sampleProvider).GetInstanceID()] = orCreateRecord;
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogDebug((object)("Failed to register VOIP sample provider: " + ex));
			}
		}

		public static IReadOnlyList<PlayerVolumeOption> GetPlayerOptions()
		{
			return (from record in Records.OrderBy<PlayerRecord, string>((PlayerRecord record) => record.DisplayName, StringComparer.OrdinalIgnoreCase)
				select new PlayerVolumeOption(record.DisplayName, record.ConfigEntry)).ToArray();
		}

		public static float GetVolume(SamplePlaybackComponent sampleProvider)
		{
			if ((Object)(object)sampleProvider != (Object)null && RecordsBySampleProviderId.TryGetValue(((Object)sampleProvider).GetInstanceID(), out var value))
			{
				return ClampVolume(value.ConfigEntry.Value);
			}
			return ClampVolume(Plugin.UnknownPlayerVolume.Value);
		}

		private static PlayerRecord GetOrCreateRecord(PlayerNetworking networking)
		{
			if ((Object)(object)networking == (Object)null || ((NetworkBehaviour)networking).isLocalPlayer)
			{
				return null;
			}
			string playerId = GetPlayerId(networking);
			if (string.IsNullOrWhiteSpace(playerId))
			{
				return null;
			}
			string playerName = GetPlayerName(networking);
			if (RecordsById.TryGetValue(playerId, out var value))
			{
				UpdateDisplayName(value, playerName);
				return value;
			}
			value = new PlayerRecord(GetDisplayName(playerName, playerId), CreateEntry(playerId, GetDisplayName(playerName, playerId)));
			RecordsById[playerId] = value;
			Records.Add(value);
			Version++;
			return value;
		}

		private static void UpdateDisplayName(PlayerRecord record, string name)
		{
			if (!string.IsNullOrWhiteSpace(name) && !string.Equals(record.DisplayName, name, StringComparison.Ordinal))
			{
				record.DisplayName = name;
				Version++;
			}
		}

		private static ConfigEntry<float> CreateEntry(string id, string displayName)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Expected O, but got Unknown
			ConfigDefinition val = new ConfigDefinition("Player Volumes", id);
			ConfigEntry<float> result = default(ConfigEntry<float>);
			if (Plugin.PluginConfig.TryGetEntry<float>(val, ref result))
			{
				return result;
			}
			ConfigEntry<float> result2 = Plugin.PluginConfig.Bind<float>(val, ClampVolume(Plugin.UnknownPlayerVolume.Value), new ConfigDescription("VOIP volume multiplier for " + displayName + ". Player ID " + id, (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 15f), Array.Empty<object>()));
			Plugin.PluginConfig.Save();
			Plugin.Log.LogInfo((object)("Created VOIP volume config entry for " + displayName + " as [Player Volumes] " + id));
			return result2;
		}

		private static string GetPlayerId(PlayerNetworking networking)
		{
			if (networking.NetworkuserPlatformId != 0L)
			{
				return networking.NetworkuserPlatformId.ToString(CultureInfo.InvariantCulture);
			}
			return "";
		}

		private static string GetPlayerName(PlayerNetworking networking)
		{
			return networking.NetworkmoderationName;
		}

		private static string GetDisplayName(string name, string id)
		{
			if (!string.IsNullOrWhiteSpace(name))
			{
				return name;
			}
			return id;
		}

		private static float ClampVolume(float value)
		{
			if (!float.IsNaN(value) && !float.IsInfinity(value))
			{
				return Math.Clamp(value, 0f, 15f);
			}
			return 1f;
		}
	}
	public readonly struct PlayerVolumeOption
	{
		public string DisplayName { get; }

		public ConfigEntry<float> ConfigEntry { get; }

		public PlayerVolumeOption(string displayName, ConfigEntry<float> configEntry)
		{
			DisplayName = displayName;
			ConfigEntry = configEntry;
		}
	}
}