Decompiled source of PlayerVoiceVolume v1.0.0

PlayerVoiceVolume.dll

Decompiled 9 hours ago
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using DG.Tweening;
using HarmonyLib;
using TMPro;
using Unity.Services.Vivox;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Localization;
using UnityEngine.Localization.Settings;
using UnityEngine.Localization.Tables;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("PlayerVoiceVolume")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("PlayerVoiceVolume")]
[assembly: AssemblyTitle("PlayerVoiceVolume")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace PlayerVoiceVolume;

internal static class GameAccess
{
	private const float LookupInterval = 1f;

	private static PlayerPanelController _players;

	private static TextChannelManager _chat;

	private static UIManager _ui;

	private static float _nextPlayersLookup;

	private static float _nextChatLookup;

	private static float _nextUiLookup;

	public static PlayerPanelController PlayerPanel
	{
		get
		{
			if ((Object)(object)_players == (Object)null && Time.unscaledTime >= _nextPlayersLookup)
			{
				_nextPlayersLookup = Time.unscaledTime + 1f;
				_players = NetworkSingleton<PlayerPanelController>.I;
			}
			return _players;
		}
		set
		{
			_players = value;
		}
	}

	public static TextChannelManager Chat
	{
		get
		{
			if ((Object)(object)_chat == (Object)null && Time.unscaledTime >= _nextChatLookup)
			{
				_nextChatLookup = Time.unscaledTime + 1f;
				_chat = NetworkSingleton<TextChannelManager>.I;
			}
			return _chat;
		}
	}

	public static UIManager UI
	{
		get
		{
			if ((Object)(object)_ui == (Object)null && Time.unscaledTime >= _nextUiLookup)
			{
				_nextUiLookup = Time.unscaledTime + 1f;
				_ui = MonoSingleton<UIManager>.I;
			}
			return _ui;
		}
	}

	public static bool IsLocalPlayer(PlayerPanelController players, int index)
	{
		TextChannelManager chat = Chat;
		if ((Object)(object)chat == (Object)null || (Object)(object)chat.MainNetTransform == (Object)null)
		{
			return false;
		}
		if (index < players.PlayerTransforms.Count)
		{
			return (Object)(object)players.PlayerTransforms[index] == (Object)(object)chat.MainNetTransform;
		}
		return false;
	}

	public static string RawPlayerName(PlayerPanelController players, int index)
	{
		PlayerController val = ((index < players.PlayerControllers.Count) ? players.PlayerControllers[index] : null);
		TMP_Text val2 = (TMP_Text)(object)(((Object)(object)val != (Object)null) ? val.PlayerNameText : null);
		if (!((Object)(object)val2 != (Object)null))
		{
			return null;
		}
		return val2.text;
	}

	public static string FilterName(string name)
	{
		if (string.IsNullOrEmpty(name))
		{
			return name;
		}
		try
		{
			BadWordFilterManager i = MonoSingleton<BadWordFilterManager>.I;
			return ((Object)(object)i != (Object)null) ? i.FilterString(name) : name;
		}
		catch (Exception)
		{
			return name;
		}
	}

	public static VoiceStatus VoiceStatusOf(PlayerPanelController players, string steamId)
	{
		int num = players.PlayerSteamIDs.IndexOf(steamId);
		if (num >= 0)
		{
			DataManager i = MonoSingleton<DataManager>.I;
			List<string> list = (((Object)(object)i != (Object)null && i.BanData != null) ? i.BanData.VoiceMutedPlayers : null);
			if (list != null && list.Contains(steamId))
			{
				return (VoiceStatus)2;
			}
			if (num < players.IsVoiceChatActive.Count && players.IsVoiceChatActive[num])
			{
				PlayerController val = ((num < players.PlayerControllers.Count) ? players.PlayerControllers[num] : null);
				PlayerVoiceController val2 = (((Object)(object)val != (Object)null) ? val.PlayerVoice : null);
				if ((Object)(object)val2 != (Object)null && val2.IsSpeaking)
				{
					return (VoiceStatus)1;
				}
				return (VoiceStatus)0;
			}
			return (VoiceStatus)3;
		}
		return (VoiceStatus)3;
	}

	public static void PlayUIChange()
	{
		try
		{
			UIManager uI = UI;
			if ((Object)(object)uI != (Object)null)
			{
				uI.PlayUIChange();
			}
		}
		catch (Exception)
		{
		}
	}

	public static void PlayUIClick()
	{
		try
		{
			UIManager uI = UI;
			if ((Object)(object)uI != (Object)null)
			{
				uI.PlayUIClick();
			}
		}
		catch (Exception)
		{
		}
	}
}
internal static class GameRefs
{
	public static readonly FieldRef<PlayerPanelController, GameObject> ServerList = Field<PlayerPanelController, GameObject>("_serverPanel");

	public static readonly FieldRef<PlayerPanelController, GameObject> BannedList = Field<PlayerPanelController, GameObject>("_bannedPanel");

	public static readonly FieldRef<PlayerPanelController, RectTransform> ServerButton = Field<PlayerPanelController, RectTransform>("_serverButtonTransform");

	public static readonly FieldRef<PlayerPanelController, RectTransform> BannedButton = Field<PlayerPanelController, RectTransform>("_bannedButtonTransform");

	public static readonly FieldRef<PlayerPanelController, Color> SelectedColor = Field<PlayerPanelController, Color>("_selectedColor");

	public static readonly FieldRef<PlayerPanelController, Color> ServerColor = Field<PlayerPanelController, Color>("_serverColor");

	public static readonly FieldRef<PlayerPanelController, Color> BannedColor = Field<PlayerPanelController, Color>("_bannedColor");

	public static readonly FieldRef<PlayerPanelController, Color> GreenColor = Field<PlayerPanelController, Color>("_greenColor");

	public static readonly FieldRef<PlayerPanelController, Color> OrangeColor = Field<PlayerPanelController, Color>("_orangeColor");

	public static readonly FieldRef<PlayerPanelController, PlayerPanelType> PanelType = Field<PlayerPanelController, PlayerPanelType>("_playerPanelType");

	public static readonly FieldRef<PlayerPanelController, GameObject> ItemPrefab = Field<PlayerPanelController, GameObject>("_playerItemPrefab");

	public static readonly FieldRef<PlayerPanelController, List<PlayerItemController>> Items = Field<PlayerPanelController, List<PlayerItemController>>("_playerItemControllers");

	public static readonly FieldRef<PlayerPanelController, RectTransform> InfoPanel = Field<PlayerPanelController, RectTransform>("_buttonInfoPanelTransfrom");

	public static readonly FieldRef<PlayerPanelController, CanvasGroup> InfoGroup = Field<PlayerPanelController, CanvasGroup>("_buttonInfoPanelCanvasGroup");

	public static readonly FieldRef<PlayerPanelController, Image> InfoHeaderBg = Field<PlayerPanelController, Image>("_buttonInfoHeaderBgImage");

	public static readonly FieldRef<PlayerPanelController, TextMeshProUGUI> InfoHeader = Field<PlayerPanelController, TextMeshProUGUI>("_buttonInfoHeaderText");

	public static readonly FieldRef<PlayerPanelController, TextMeshProUGUI> InfoText = Field<PlayerPanelController, TextMeshProUGUI>("_buttonInfoText");

	public static readonly FieldRef<PlayerItemController, string> ItemSteamId = Field<PlayerItemController, string>("_playerSteamId");

	public static readonly FieldRef<PlayerItemController, TextMeshProUGUI> ItemName = Field<PlayerItemController, TextMeshProUGUI>("_playerNameText");

	public static readonly FieldRef<PlayerItemController, Button> ItemReport = Field<PlayerItemController, Button>("_reportButton");

	public static readonly FieldRef<PlayerItemController, Button> ItemBan = Field<PlayerItemController, Button>("_banButton");

	public static readonly FieldRef<PlayerItemController, Button> ItemSteam = Field<PlayerItemController, Button>("_steamButton");

	public static readonly FieldRef<PlayerItemController, Button> ItemMute = Field<PlayerItemController, Button>("_muteButton");

	public static readonly FieldRef<PlayerItemController, Button> ItemIgnore = Field<PlayerItemController, Button>("_ignoreButton");

	public static readonly FieldRef<PlayerItemController, Button> ItemVoiceMute = Field<PlayerItemController, Button>("_voiceMuteButton");

	public static readonly FieldRef<PlayerItemController, GameObject> ItemSync = Field<PlayerItemController, GameObject>("_syncButtonObject");

	public static readonly FieldRef<PlayerItemController, GameObject> ItemSyncedWithMe = Field<PlayerItemController, GameObject>("_syncWithMeObject");

	public static readonly FieldRef<PlayerItemController, Image> ItemVoiceIcon = Field<PlayerItemController, Image>("_voiceMuteImage");

	public static readonly FieldRef<PlayerItemController, Image> ItemVoiceBg = Field<PlayerItemController, Image>("_voiceMuteBgImage");

	public static readonly FieldRef<PlayerItemController, Sprite> ItemMicOpen = Field<PlayerItemController, Sprite>("_voiceChatOpen");

	public static readonly FieldRef<PlayerItemController, Sprite> ItemMicMuted = Field<PlayerItemController, Sprite>("_voiceChatMute");

	public static readonly FieldRef<SettingsController, Slider> SettingsVoiceSlider = Field<SettingsController, Slider>("_voiceVolumeSlider");

	public static TField Get<TObject, TField>(FieldRef<TObject, TField> field, TObject instance) where TObject : class
	{
		if (field == null || instance == null)
		{
			return default(TField);
		}
		return field.Invoke(instance);
	}

	private static FieldRef<TObject, TField> Field<TObject, TField>(string name)
	{
		try
		{
			return AccessTools.FieldRefAccess<TObject, TField>(name);
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("Game field " + typeof(TObject).Name + "." + name + " not found (" + ex.Message + "); some UI may be missing."));
			return null;
		}
	}
}
internal static class Icons
{
	private static Sprite _reset;

	public static Sprite Reset
	{
		get
		{
			if ((Object)(object)_reset == (Object)null)
			{
				_reset = CreateResetIcon(64);
			}
			return _reset;
		}
	}

	private static Sprite CreateResetIcon(int size)
	{
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: 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_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0050: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: 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_0062: 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_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: 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_0079: 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_0083: 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_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_0095: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a0: 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_00ae: 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_00c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0204: Unknown result type (might be due to invalid IL or missing references)
		//IL_020b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0215: Expected O, but got Unknown
		//IL_0237: Unknown result type (might be due to invalid IL or missing references)
		//IL_0246: Unknown result type (might be due to invalid IL or missing references)
		//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_0133: Unknown result type (might be due to invalid IL or missing references)
		//IL_0135: Unknown result type (might be due to invalid IL or missing references)
		//IL_0151: 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_0155: Unknown result type (might be due to invalid IL or missing references)
		//IL_015a: Unknown result type (might be due to invalid IL or missing references)
		//IL_016a: Unknown result type (might be due to invalid IL or missing references)
		//IL_016c: Unknown result type (might be due to invalid IL or missing references)
		//IL_016e: 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)
		Vector2 val = default(Vector2);
		((Vector2)(ref val))..ctor(0.5f, 0.5f);
		float num = 0.6981317f;
		Vector2 val2 = default(Vector2);
		((Vector2)(ref val2))..ctor(Mathf.Cos(num), Mathf.Sin(num));
		Vector2 val3 = default(Vector2);
		((Vector2)(ref val3))..ctor(val2.y, 0f - val2.x);
		Vector2 val4 = val + val2 * 0.31f;
		Vector2 a = val4 + val3 * 0.17f;
		Vector2 b = val4 + val2 * 0.16f - val3 * 0.03f;
		Vector2 c = val4 - val2 * 0.16f - val3 * 0.03f;
		float num2 = 5.5850534f;
		Vector2 val5 = val + new Vector2(Mathf.Cos(num2), Mathf.Sin(num2)) * 0.31f;
		Color32[] array = (Color32[])(object)new Color32[size * size];
		Vector2 val6 = default(Vector2);
		for (int i = 0; i < size; i++)
		{
			for (int j = 0; j < size; j++)
			{
				int num3 = 0;
				for (int k = 0; k < 4; k++)
				{
					for (int l = 0; l < 4; l++)
					{
						((Vector2)(ref val6))..ctor(((float)j + ((float)l + 0.5f) / 4f) / (float)size, ((float)i + ((float)k + 0.5f) / 4f) / (float)size);
						if (!OnArc(val6, val, 0.31f, 0.11f, 40f, 320f))
						{
							Vector2 val7 = val6 - val5;
							if (!(((Vector2)(ref val7)).sqrMagnitude <= 0.003025f) && !InTriangle(val6, a, b, c))
							{
								continue;
							}
						}
						num3++;
					}
				}
				byte b2 = (byte)(255 * num3 / 16);
				array[i * size + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, b2);
			}
		}
		Texture2D val8 = new Texture2D(size, size, (TextureFormat)4, false)
		{
			name = "PlayerVoiceVolume_Reset",
			filterMode = (FilterMode)1,
			wrapMode = (TextureWrapMode)1,
			hideFlags = (HideFlags)61
		};
		val8.SetPixels32(array);
		val8.Apply(false, true);
		Sprite obj = Sprite.Create(val8, new Rect(0f, 0f, (float)size, (float)size), new Vector2(0.5f, 0.5f), (float)size);
		((Object)obj).name = ((Object)val8).name;
		((Object)obj).hideFlags = (HideFlags)61;
		return obj;
	}

	private static bool OnArc(Vector2 p, Vector2 center, float radius, float stroke, float startDeg, float endDeg)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: 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_0027: Unknown result type (might be due to invalid IL or missing references)
		Vector2 val = p - center;
		if (Mathf.Abs(((Vector2)(ref val)).magnitude - radius) > stroke * 0.5f)
		{
			return false;
		}
		float num = Mathf.Atan2(val.y, val.x) * 57.29578f;
		if (num < 0f)
		{
			num += 360f;
		}
		if (num >= startDeg)
		{
			return num <= endDeg;
		}
		return false;
	}

	private static bool InTriangle(Vector2 p, Vector2 a, Vector2 b, Vector2 c)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_000a: 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_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		float num = Cross(p, a, b);
		float num2 = Cross(p, b, c);
		float num3 = Cross(p, c, a);
		bool flag = num < 0f || num2 < 0f || num3 < 0f;
		bool flag2 = num > 0f || num2 > 0f || num3 > 0f;
		return !(flag && flag2);
	}

	private static float Cross(Vector2 p, Vector2 a, Vector2 b)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: 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_0028: 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)
		return (p.x - b.x) * (a.y - b.y) - (a.x - b.x) * (p.y - b.y);
	}
}
internal static class Patches
{
	public static void Apply(Harmony harmony)
	{
		Postfix(harmony, "Start", "PlayerListStarted");
		Postfix(harmony, "ButtonServer", "ServerTabSelected");
		Postfix(harmony, "ButtonBanned", "BannedTabSelected");
		Postfix(harmony, "ButtonClosePanel", "PlayerListClosed");
		Postfix(harmony, "UpdateServerPanelOnChange", "PlayersChanged");
	}

	private static void Postfix(Harmony harmony, string method, string patch)
	{
		//IL_0047: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Expected O, but got Unknown
		try
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(PlayerPanelController), method, (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				Plugin.Log.LogWarning((object)("PlayerPanelController." + method + " not found; the Voice tab may not work."));
			}
			else
			{
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), patch, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}
		catch (Exception arg)
		{
			Plugin.Log.LogError((object)$"Could not patch PlayerPanelController.{method}: {arg}");
		}
	}

	private static void PlayerListStarted(PlayerPanelController __instance)
	{
		Run(delegate
		{
			GameAccess.PlayerPanel = __instance;
			VoiceTab.EnsureInjected(__instance);
		});
	}

	private static void ServerTabSelected(PlayerPanelController __instance)
	{
		Run(delegate
		{
			GameTabSelected(__instance, GameRefs.Get<PlayerPanelController, RectTransform>(GameRefs.ServerButton, __instance));
		});
	}

	private static void BannedTabSelected(PlayerPanelController __instance)
	{
		Run(delegate
		{
			GameTabSelected(__instance, GameRefs.Get<PlayerPanelController, RectTransform>(GameRefs.BannedButton, __instance));
		});
	}

	private static void GameTabSelected(PlayerPanelController players, RectTransform button)
	{
		VoiceTab.EnsureInjected(players);
		VoiceTab current = VoiceTab.Current;
		if ((Object)(object)current != (Object)null && (Object)(object)current.Panel == (Object)(object)players)
		{
			current.OnGameTabSelected(button);
		}
	}

	private static void PlayerListClosed()
	{
		Run(delegate
		{
			Plugin.Instance.Store.Save();
		});
	}

	private static void PlayersChanged()
	{
		Run(delegate
		{
			VoiceTab current = VoiceTab.Current;
			if ((Object)(object)current != (Object)null)
			{
				current.MarkPlayersChanged();
			}
		});
	}

	private static void Run(Action action)
	{
		try
		{
			action();
		}
		catch (Exception ex)
		{
			Plugin.Log.LogError((object)("Player list hook failed: " + ex));
		}
	}
}
[BepInPlugin("ontogether.playervoicevolume", "PlayerVoiceVolume", "1.0.0")]
[BepInProcess("OnTogether.exe")]
public sealed class Plugin : BaseUnityPlugin
{
	public const string PluginGuid = "ontogether.playervoicevolume";

	public const string PluginName = "PlayerVoiceVolume";

	public const string PluginVersion = "1.0.0";

	internal ConfigEntry<int> MaxVolume;

	internal ConfigEntry<int> DefaultVolume;

	private VoiceApplier _applier;

	private Harmony _harmony;

	internal static Plugin Instance { get; private set; }

	internal static ManualLogSource Log { get; private set; }

	internal VolumeStore Store { get; private set; }

	private void Awake()
	{
		//IL_003d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Expected O, but got Unknown
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Expected O, but got Unknown
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c3: Expected O, but got Unknown
		Instance = this;
		Log = ((BaseUnityPlugin)this).Logger;
		MaxVolume = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MaxVolumePercent", 200, new ConfigDescription("Right end of the per-player volume slider, in percent. 100% leaves a player unchanged; every doubling is +10 dB, so 200% sounds about twice as loud. Values above 200% can distort loud voices.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(100, 400), Array.Empty<object>()));
		DefaultVolume = ((BaseUnityPlugin)this).Config.Bind<int>("General", "DefaultVolumePercent", 100, new ConfigDescription("Volume of players you have not adjusted, in percent. The reset button on a player returns them to this value.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 400), Array.Empty<object>()));
		Store = new VolumeStore(Path.Combine(Paths.ConfigPath, "ontogether.playervoicevolume.volumes.json"));
		Store.Load();
		_applier = new VoiceApplier();
		_harmony = new Harmony("ontogether.playervoicevolume");
		Patches.Apply(_harmony);
		((BaseUnityPlugin)this).Config.SettingChanged += OnSettingChanged;
		Log.LogInfo((object)string.Format("{0} {1} loaded; {2} saved player volume(s).", "PlayerVoiceVolume", "1.0.0", Store.Count));
	}

	private void Update()
	{
		_applier.Tick();
		Store.SaveIfDue();
	}

	internal int VolumeFor(string steamId)
	{
		int percent;
		return Mathf.Clamp(Store.TryGet(steamId, out percent) ? percent : DefaultVolume.Value, 0, MaxVolume.Value);
	}

	internal bool HasSavedVolume(string steamId)
	{
		int percent;
		return Store.TryGet(steamId, out percent);
	}

	internal void SetVolume(string steamId, string playerName, int percent)
	{
		Store.Set(steamId, playerName, percent);
		_applier.ApplySoon();
	}

	internal void ResetVolume(string steamId)
	{
		Store.Remove(steamId);
		_applier.ApplySoon();
	}

	private void OnSettingChanged(object sender, SettingChangedEventArgs e)
	{
		_applier.ApplySoon();
		VoiceTab current = VoiceTab.Current;
		if ((Object)(object)current != (Object)null)
		{
			current.RefreshVolumes();
		}
	}

	private void OnApplicationQuit()
	{
		Store.Save();
	}

	private void OnDestroy()
	{
		((BaseUnityPlugin)this).Config.SettingChanged -= OnSettingChanged;
		Store.Save();
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
		}
	}
}
internal static class Strings
{
	private static string _language = "en";

	public static string Tab => Pick("Voice", "Голос", "Voix", "Voz", "Voz", "ボイス", "语音");

	public static string Hint => Pick("only for you", "только для вас", "pour vous seulement", "solo para ti", "só para você", "自分にだけ反映", "仅对你生效");

	public static string NoPlayers => Pick("No other players here yet.", "Других игроков пока нет.", "Aucun autre joueur ici pour l'instant.", "Todavía no hay otros jugadores aquí.", "Ainda não há outros jogadores aqui.", "まだ他のプレイヤーはいません。", "这里还没有其他玩家。");

	public static string ResetTitle => Pick("Reset Volume", "Сбросить громкость", "Réinitialiser le volume", "Restablecer volumen", "Redefinir volume", "音量をリセット", "重置音量");

	public static string ResetInfo => Pick("Set this player's volume back to {0}.", "Вернуть громкость этого игрока к {0}.", "Remettre le volume de ce joueur à {0}.", "Devuelve el volumen de este jugador a {0}.", "Volta o volume deste jogador para {0}.", "このプレイヤーの音量を{0}に戻します。", "将该玩家的音量恢复为{0}。");

	public static string Header => GameString("VoiceVolume") ?? Pick("Voice Volume", "Громкость голоса", "Volume de la voix", "Volumen de voz", "Volume da voz", "ボイス音量", "语音音量");

	public static void Refresh()
	{
		try
		{
			_language = CurrentLanguage() ?? "en";
		}
		catch (Exception)
		{
			_language = "en";
		}
	}

	private static string CurrentLanguage()
	{
		//IL_0013: 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)
		Locale selectedLocale = LocalizationSettings.SelectedLocale;
		object obj;
		if (!((Object)(object)selectedLocale != (Object)null))
		{
			obj = null;
		}
		else
		{
			LocaleIdentifier identifier = selectedLocale.Identifier;
			obj = ((LocaleIdentifier)(ref identifier)).Code;
		}
		string text = (string)obj;
		if (string.IsNullOrEmpty(text))
		{
			return null;
		}
		int num = text.IndexOfAny(new char[2] { '-', '_' });
		return ((num > 0) ? text.Substring(0, num) : text).ToLowerInvariant();
	}

	private static string GameString(string key)
	{
		//IL_000a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			string localizedString = LocalizationSettings.StringDatabase.GetLocalizedString(TableReference.op_Implicit("General"), TableEntryReference.op_Implicit(key), (Locale)null, (FallbackBehavior)0, Array.Empty<object>());
			if (string.IsNullOrEmpty(localizedString) || localizedString.StartsWith("No translation", StringComparison.OrdinalIgnoreCase))
			{
				return null;
			}
			return localizedString;
		}
		catch (Exception)
		{
			return null;
		}
	}

	private static string Pick(string en, string ru, string fr, string es, string pt, string ja, string zh)
	{
		return _language switch
		{
			"ru" => ru, 
			"fr" => fr, 
			"es" => es, 
			"pt" => pt, 
			"ja" => ja, 
			"zh" => zh, 
			_ => en, 
		};
	}
}
internal static class UiUtil
{
	public static void RemoveLocalization(GameObject root)
	{
		MonoBehaviour[] componentsInChildren = root.GetComponentsInChildren<MonoBehaviour>(true);
		foreach (MonoBehaviour val in componentsInChildren)
		{
			if ((Object)(object)val != (Object)null && ((object)val).GetType().Name == "LocalizeStringEvent")
			{
				Object.DestroyImmediate((Object)(object)val);
			}
		}
	}

	public static void SetOnClick(Button button, Action action)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Expected O, but got Unknown
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002f: Expected O, but got Unknown
		button.onClick = new ButtonClickedEvent();
		((UnityEvent)button.onClick).AddListener((UnityAction)delegate
		{
			try
			{
				action();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("UI action failed: " + ex));
			}
		});
	}

	public static void DisableNavigation(Selectable selectable)
	{
		//IL_0003: 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)
		Navigation navigation = default(Navigation);
		((Navigation)(ref navigation)).mode = (Mode)0;
		selectable.navigation = navigation;
	}

	public static void Place(RectTransform rect, Vector2 anchor, Vector2 pivot, Vector2 position, Vector2 size)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: 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_001d: Unknown result type (might be due to invalid IL or missing references)
		rect.anchorMin = anchor;
		rect.anchorMax = anchor;
		rect.pivot = pivot;
		rect.anchoredPosition = position;
		rect.sizeDelta = size;
	}

	public static void AddHover(GameObject target, Action enter, Action exit)
	{
		HoverRelay hoverRelay = target.GetComponent<HoverRelay>();
		if ((Object)(object)hoverRelay == (Object)null)
		{
			hoverRelay = target.AddComponent<HoverRelay>();
		}
		hoverRelay.Enter = enter;
		hoverRelay.Exit = exit;
	}

	public static Image NewImage(string name, Transform parent, Sprite sprite, Color color, float pixelsPerUnit)
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: 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_0079: Unknown result type (might be due to invalid IL or missing references)
		GameObject val = new GameObject(name, new Type[3]
		{
			typeof(RectTransform),
			typeof(CanvasRenderer),
			typeof(Image)
		})
		{
			layer = ((Component)parent).gameObject.layer
		};
		val.transform.SetParent(parent, false);
		Image component = val.GetComponent<Image>();
		component.sprite = sprite;
		component.type = (Type)(((Object)(object)sprite != (Object)null) ? 1 : 0);
		component.pixelsPerUnitMultiplier = pixelsPerUnit;
		((Graphic)component).color = color;
		return component;
	}

	public static RectTransform NewRect(string name, Transform parent)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: 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)
		//IL_0042: Expected O, but got Unknown
		GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) })
		{
			layer = ((Component)parent).gameObject.layer
		};
		val.transform.SetParent(parent, false);
		return (RectTransform)val.transform;
	}

	public static void Stretch(RectTransform rect, Vector2 anchorMin, Vector2 anchorMax, Vector2 sizeDelta, Vector2 position)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		rect.anchorMin = anchorMin;
		rect.anchorMax = anchorMax;
		rect.pivot = new Vector2(0.5f, 0.5f);
		rect.sizeDelta = sizeDelta;
		rect.anchoredPosition = position;
	}
}
internal sealed class HoverRelay : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler
{
	internal Action Enter;

	internal Action Exit;

	private bool _hovered;

	public void OnPointerEnter(PointerEventData eventData)
	{
		_hovered = true;
		Invoke(Enter);
	}

	public void OnPointerExit(PointerEventData eventData)
	{
		_hovered = false;
		Invoke(Exit);
	}

	private void OnDisable()
	{
		if (_hovered)
		{
			_hovered = false;
			Invoke(Exit);
		}
	}

	private static void Invoke(Action action)
	{
		if (action == null)
		{
			return;
		}
		try
		{
			action();
		}
		catch (Exception ex)
		{
			Plugin.Log.LogWarning((object)("Hover action failed: " + ex.Message));
		}
	}
}
internal sealed class VoiceApplier
{
	private struct Request
	{
		public VivoxParticipant Participant;

		public int Value;

		public float Time;
	}

	private const float Interval = 0.5f;

	private const float SoonDelay = 0.1f;

	private const float RetryAfter = 3f;

	private readonly Dictionary<string, Request> _requests = new Dictionary<string, Request>(StringComparer.Ordinal);

	private float _nextRun;

	private string _lastError;

	public void ApplySoon()
	{
		_nextRun = Mathf.Min(_nextRun, Time.unscaledTime + 0.1f);
	}

	public void Tick()
	{
		float unscaledTime = Time.unscaledTime;
		if (unscaledTime < _nextRun)
		{
			return;
		}
		_nextRun = unscaledTime + 0.5f;
		try
		{
			ApplyAll(unscaledTime);
		}
		catch (Exception e)
		{
			Report(e);
		}
	}

	private void Report(Exception e)
	{
		string text = e.GetType().Name + ": " + e.Message;
		if (!(text == _lastError))
		{
			_lastError = text;
			Plugin.Log.LogWarning((object)("Could not apply player volumes: " + e));
		}
	}

	private void ApplyAll(float now)
	{
		IVivoxService instance = VivoxService.Instance;
		if (instance == null)
		{
			return;
		}
		ReadOnlyDictionary<string, ReadOnlyCollection<VivoxParticipant>> activeChannels = instance.ActiveChannels;
		if (activeChannels == null || activeChannels.Count == 0)
		{
			return;
		}
		PlayerPanelController playerPanel = GameAccess.PlayerPanel;
		if ((Object)(object)playerPanel == (Object)null)
		{
			return;
		}
		foreach (KeyValuePair<string, ReadOnlyCollection<VivoxParticipant>> item in activeChannels)
		{
			if (item.Value == null)
			{
				continue;
			}
			foreach (VivoxParticipant item2 in item.Value)
			{
				try
				{
					ApplyTo(item2, playerPanel, now);
				}
				catch (Exception e)
				{
					Report(e);
				}
			}
		}
		if (_requests.Count > 64)
		{
			_requests.Clear();
		}
	}

	private void ApplyTo(VivoxParticipant participant, PlayerPanelController players, float now)
	{
		if (participant == null || participant.IsSelf)
		{
			return;
		}
		string playerId = participant.PlayerId;
		int num = ((players.VivoxIDs != null) ? players.VivoxIDs.IndexOf(playerId) : (-1));
		if (num >= 0 && players.PlayerSteamIDs != null && num < players.PlayerSteamIDs.Count)
		{
			int num2 = VolumeMath.ToVivox(Plugin.Instance.VolumeFor(players.PlayerSteamIDs[num]));
			Request value;
			if (participant.LocalVolume == num2)
			{
				_requests.Remove(playerId);
			}
			else if (!_requests.TryGetValue(playerId, out value) || value.Participant != participant || value.Value != num2 || !(now - value.Time < 3f))
			{
				participant.SetLocalVolume(num2);
				_requests[playerId] = new Request
				{
					Participant = participant,
					Value = num2,
					Time = now
				};
			}
		}
	}
}
internal sealed class VoiceRow : MonoBehaviour
{
	private const float GapAfterName = 18f;

	private const float SliderX = 474f;

	private const float SliderWidth = 360f;

	private const float SliderHeight = 30f;

	private const float ValueX = 850f;

	private const float ValueWidth = 140f;

	private const float ResetButtonCenterFromRight = 42.5f;

	private const float ResetIconSize = 40f;

	private VoiceTab _tab;

	private TMP_Text _name;

	private Slider _slider;

	private CanvasGroup _sliderGroup;

	private TMP_Text _value;

	private RectTransform _voiceButton;

	private Image _voiceBackground;

	private Image _voiceIcon;

	private Sprite _micOpen;

	private Sprite _micMuted;

	private RectTransform _resetButton;

	private string _rawName;

	private bool _binding;

	private VoiceStatus? _shownStatus;

	internal string SteamId { get; private set; }

	internal string DisplayName { get; private set; }

	internal VoiceStatus Status { get; private set; } = (VoiceStatus)3;

	internal static VoiceRow Create(VoiceTab tab, GameObject prefab, Transform parent, Slider sliderTemplate, Sprite panelSprite)
	{
		GameObject val = Object.Instantiate<GameObject>(prefab, parent, false);
		((Object)val).name = "Item_PlayerVoiceVolume";
		VoiceRow voiceRow = val.AddComponent<VoiceRow>();
		voiceRow._tab = tab;
		try
		{
			voiceRow.Build(val.GetComponent<PlayerItemController>(), sliderTemplate, panelSprite);
			return voiceRow;
		}
		catch
		{
			Object.Destroy((Object)(object)val);
			throw;
		}
	}

	private void Build(PlayerItemController item, Slider sliderTemplate, Sprite panelSprite)
	{
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Expected O, but got Unknown
		//IL_021f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0239: Unknown result type (might be due to invalid IL or missing references)
		//IL_024b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0255: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b5: Expected O, but got Unknown
		//IL_02f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0302: Unknown result type (might be due to invalid IL or missing references)
		//IL_0311: Unknown result type (might be due to invalid IL or missing references)
		//IL_0320: Unknown result type (might be due to invalid IL or missing references)
		//IL_032f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0339: Expected O, but got Unknown
		//IL_03ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_03dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_03e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f3: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0409: Unknown result type (might be due to invalid IL or missing references)
		//IL_0441: Unknown result type (might be due to invalid IL or missing references)
		//IL_044b: Expected O, but got Unknown
		//IL_0451: Unknown result type (might be due to invalid IL or missing references)
		//IL_0456: Unknown result type (might be due to invalid IL or missing references)
		//IL_045a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0482: Unknown result type (might be due to invalid IL or missing references)
		//IL_0487: Unknown result type (might be due to invalid IL or missing references)
		//IL_048b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0475: Unknown result type (might be due to invalid IL or missing references)
		//IL_0490: Unknown result type (might be due to invalid IL or missing references)
		//IL_04b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_04c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_04d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_04d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_050c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0527: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)item == (Object)null)
		{
			throw new InvalidOperationException("the player row prefab has no PlayerItemController");
		}
		TextMeshProUGUI val = GameRefs.Get<PlayerItemController, TextMeshProUGUI>(GameRefs.ItemName, item);
		Button val2 = GameRefs.Get<PlayerItemController, Button>(GameRefs.ItemVoiceMute, item);
		if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
		{
			throw new InvalidOperationException("the player row layout has changed");
		}
		_name = (TMP_Text)(object)val;
		_voiceButton = (RectTransform)((Component)val2).transform;
		_voiceBackground = GameRefs.Get<PlayerItemController, Image>(GameRefs.ItemVoiceBg, item);
		_voiceIcon = GameRefs.Get<PlayerItemController, Image>(GameRefs.ItemVoiceIcon, item);
		_micOpen = GameRefs.Get<PlayerItemController, Sprite>(GameRefs.ItemMicOpen, item);
		_micMuted = GameRefs.Get<PlayerItemController, Sprite>(GameRefs.ItemMicMuted, item);
		Button val3 = GameRefs.Get<PlayerItemController, Button>(GameRefs.ItemMute, item);
		Transform val4 = (((Object)(object)val3 != (Object)null) ? ((Component)val3).transform.parent : null);
		List<GameObject> list = new List<GameObject>();
		Button[] array = (Button[])(object)new Button[4]
		{
			GameRefs.Get<PlayerItemController, Button>(GameRefs.ItemReport, item),
			GameRefs.Get<PlayerItemController, Button>(GameRefs.ItemBan, item),
			GameRefs.Get<PlayerItemController, Button>(GameRefs.ItemSteam, item),
			GameRefs.Get<PlayerItemController, Button>(GameRefs.ItemIgnore, item)
		};
		foreach (Button val5 in array)
		{
			if ((Object)(object)val5 != (Object)null)
			{
				list.Add(((Component)val5).gameObject);
			}
		}
		list.Add(GameRefs.Get<PlayerItemController, GameObject>(GameRefs.ItemSync, item));
		list.Add(GameRefs.Get<PlayerItemController, GameObject>(GameRefs.ItemSyncedWithMe, item));
		foreach (GameObject item2 in list)
		{
			if ((Object)(object)item2 != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)item2);
			}
		}
		PlayerPanelButtonController[] componentsInChildren = ((Component)this).GetComponentsInChildren<PlayerPanelButtonController>(true);
		for (int i = 0; i < componentsInChildren.Length; i++)
		{
			Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
		}
		Object.DestroyImmediate((Object)(object)item);
		UiUtil.SetOnClick(val2, OnVoiceButton);
		UiUtil.AddHover(((Component)val2).gameObject, ShowVoiceInfo, HideInfo);
		UiUtil.DisableNavigation((Selectable)(object)val2);
		RectTransform rectTransform = _name.rectTransform;
		float num = 456f - rectTransform.anchoredPosition.x;
		if (num > 50f && num < rectTransform.sizeDelta.x)
		{
			rectTransform.sizeDelta = new Vector2(num, rectTransform.sizeDelta.y);
		}
		_name.overflowMode = (TextOverflowModes)1;
		_slider = (((Object)(object)sliderTemplate != (Object)null) ? Object.Instantiate<Slider>(sliderTemplate, ((Component)this).transform, false) : BuildSlider(((Component)this).transform, panelSprite));
		((Object)_slider).name = "Slider_Volume";
		_slider.onValueChanged = new SliderEvent();
		UiUtil.DisableNavigation((Selectable)(object)_slider);
		_slider.direction = (Direction)0;
		_slider.minValue = 0f;
		_slider.wholeNumbers = true;
		UiUtil.Place((RectTransform)((Component)_slider).transform, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(474f, 0f), new Vector2(360f, 30f));
		_sliderGroup = ((Component)_slider).gameObject.AddComponent<CanvasGroup>();
		((UnityEvent<float>)(object)_slider.onValueChanged).AddListener((UnityAction<float>)OnSliderChanged);
		_value = Object.Instantiate<GameObject>(((Component)_name).gameObject, ((Component)this).transform, false).GetComponent<TMP_Text>();
		((Object)_value).name = "Text_Volume";
		_value.alignment = (TextAlignmentOptions)514;
		_value.overflowMode = (TextOverflowModes)0;
		UiUtil.Place(_value.rectTransform, new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(850f, rectTransform.anchoredPosition.y), new Vector2(140f, rectTransform.sizeDelta.y));
		Button val6 = (((Object)(object)val3 != (Object)null) ? val3 : BuildButton(((Component)this).transform, panelSprite));
		((Object)val6).name = "Button_ResetVolume";
		_resetButton = (RectTransform)((Component)val6).transform;
		Rect rect = _resetButton.rect;
		? val7;
		if (!(((Rect)(ref rect)).size.x > 1f))
		{
			val7 = new Vector2(65f, 65f);
		}
		else
		{
			rect = _resetButton.rect;
			val7 = ((Rect)(ref rect)).size;
		}
		Vector2 size = (Vector2)val7;
		((Transform)_resetButton).SetParent(((Component)this).transform, false);
		UiUtil.Place(_resetButton, new Vector2(1f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(-42.5f, 0f), size);
		Image val8 = FindIcon(val6);
		if ((Object)(object)val8 != (Object)null)
		{
			val8.sprite = Icons.Reset;
			val8.preserveAspect = true;
			((Graphic)val8).rectTransform.anchoredPosition = Vector2.zero;
			((Graphic)val8).rectTransform.sizeDelta = new Vector2(40f, 40f);
		}
		UiUtil.SetOnClick(val6, OnResetButton);
		UiUtil.AddHover(((Component)val6).gameObject, ShowResetInfo, HideInfo);
		UiUtil.DisableNavigation((Selectable)(object)val6);
		if ((Object)(object)val4 != (Object)null && (Object)(object)val4 != (Object)(object)((Component)this).transform && val4.childCount == 0)
		{
			Object.DestroyImmediate((Object)(object)((Component)val4).gameObject);
		}
	}

	internal void Bind(string steamId, string rawName, bool force)
	{
		bool num = steamId != SteamId;
		SteamId = steamId;
		if (num || rawName != _rawName)
		{
			_rawName = rawName;
			DisplayName = GameAccess.FilterName(rawName) ?? string.Empty;
			_name.text = DisplayName;
			Plugin.Instance.Store.RememberName(steamId, DisplayName);
		}
		if (num || force)
		{
			ShowVolume(Plugin.Instance.VolumeFor(steamId));
			_shownStatus = null;
		}
	}

	private void ShowVolume(int percent)
	{
		_binding = true;
		try
		{
			_slider.maxValue = Plugin.Instance.MaxVolume.Value;
			_slider.SetValueWithoutNotify((float)percent);
		}
		finally
		{
			_binding = false;
		}
		_value.text = VolumeMath.Format(percent);
	}

	private void OnSliderChanged(float value)
	{
		if (!_binding && !string.IsNullOrEmpty(SteamId))
		{
			int percent = Mathf.RoundToInt(value);
			Plugin.Instance.SetVolume(SteamId, DisplayName, percent);
			_value.text = VolumeMath.Format(percent);
		}
	}

	private void OnResetButton()
	{
		if (!string.IsNullOrEmpty(SteamId))
		{
			Plugin.Instance.ResetVolume(SteamId);
			ShowVolume(Plugin.Instance.VolumeFor(SteamId));
			GameAccess.PlayUIClick();
		}
	}

	private void OnVoiceButton()
	{
		PlayerPanelController panel = _tab.Panel;
		PlayerItemController val = FindGameRow(panel);
		if ((Object)(object)val == (Object)null)
		{
			panel.UpdateServerPanel();
			val = FindGameRow(panel);
		}
		if ((Object)(object)val == (Object)null)
		{
			Plugin.Log.LogWarning((object)("No player list entry for " + DisplayName + "; cannot toggle the voice mute."));
			return;
		}
		val.ButtonVoiceMutePlayer();
		RefreshStatus();
		ShowVoiceInfo();
	}

	private PlayerItemController FindGameRow(PlayerPanelController players)
	{
		List<PlayerItemController> list = GameRefs.Get<PlayerPanelController, List<PlayerItemController>>(GameRefs.Items, players);
		if (list == null)
		{
			return null;
		}
		foreach (PlayerItemController item in list)
		{
			if ((Object)(object)item != (Object)null && ((Component)item).gameObject.activeSelf && GameRefs.Get<PlayerItemController, string>(GameRefs.ItemSteamId, item) == SteamId)
			{
				return item;
			}
		}
		return null;
	}

	internal void RefreshStatus()
	{
		//IL_002b: 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)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_006a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Invalid comparison between Unknown and I4
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Invalid comparison between Unknown and I4
		//IL_0093: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: 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_00b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Invalid comparison between Unknown and I4
		//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fd: Invalid comparison between Unknown and I4
		//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0100: Unknown result type (might be due to invalid IL or missing references)
		//IL_0106: Invalid comparison between Unknown and I4
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		PlayerPanelController panel = _tab.Panel;
		if ((Object)(object)panel == (Object)null || string.IsNullOrEmpty(SteamId))
		{
			return;
		}
		Status = GameAccess.VoiceStatusOf(panel, SteamId);
		if (_shownStatus == (VoiceStatus?)Status)
		{
			return;
		}
		_shownStatus = Status;
		bool flag = (int)Status == 2;
		if ((Object)(object)_voiceBackground != (Object)null)
		{
			((Graphic)_voiceBackground).color = (flag ? panel.RedColor : panel.IconDeactiveColor);
		}
		if ((Object)(object)_voiceIcon != (Object)null)
		{
			VoiceStatus status = Status;
			if ((int)status != 1)
			{
				if ((int)status == 2)
				{
					((Graphic)_voiceIcon).color = panel.IconColor;
				}
				else
				{
					((Graphic)_voiceIcon).color = panel.MicIconInactiveColor;
				}
			}
			else
			{
				((Graphic)_voiceIcon).color = panel.IconActiveColor;
			}
			Sprite val = (((int)Status == 2 || (int)Status == 3) ? _micMuted : _micOpen);
			if ((Object)(object)val != (Object)null)
			{
				_voiceIcon.sprite = val;
			}
		}
		_sliderGroup.alpha = (flag ? 0.45f : 1f);
	}

	private void ShowVoiceInfo()
	{
		//IL_001e: Unknown result type (might be due to invalid IL or missing references)
		PlayerPanelController panel = _tab.Panel;
		if ((Object)(object)panel != (Object)null)
		{
			panel.OpenButtonInfoPopup((PlayerPanelButtonType)6, _voiceButton, Status, (PomoSyncStatus)0);
		}
	}

	private void ShowResetInfo()
	{
		int percent = Mathf.Clamp(Plugin.Instance.DefaultVolume.Value, 0, Plugin.Instance.MaxVolume.Value);
		_tab.ShowInfo(_resetButton, Strings.ResetTitle, string.Format(Strings.ResetInfo, VolumeMath.Format(percent)));
	}

	private void HideInfo()
	{
		PlayerPanelController val = (((Object)(object)_tab != (Object)null) ? _tab.Panel : null);
		if ((Object)(object)val != (Object)null)
		{
			val.CloseButtonInfoPopup();
		}
	}

	private static Image FindIcon(Button button)
	{
		Image[] componentsInChildren = ((Component)button).GetComponentsInChildren<Image>(true);
		foreach (Image val in componentsInChildren)
		{
			if ((Object)(object)((Component)val).gameObject != (Object)(object)((Component)button).gameObject)
			{
				return val;
			}
		}
		return null;
	}

	private static Slider BuildSlider(Transform parent, Sprite sprite)
	{
		//IL_0022: 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_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_007a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: 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_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0100: Unknown result type (might be due to invalid IL or missing references)
		//IL_0117: Unknown result type (might be due to invalid IL or missing references)
		//IL_011c: Unknown result type (might be due to invalid IL or missing references)
		//IL_012b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0130: Unknown result type (might be due to invalid IL or missing references)
		//IL_0150: Unknown result type (might be due to invalid IL or missing references)
		//IL_0168: 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_0186: Unknown result type (might be due to invalid IL or missing references)
		//IL_018b: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
		RectTransform val = UiUtil.NewRect("Slider", parent);
		UiUtil.Stretch(((Graphic)UiUtil.NewImage("Background", (Transform)(object)val, sprite, new Color(0.773f, 0.714f, 0.682f), 10f)).rectTransform, new Vector2(0f, 0.25f), new Vector2(1f, 0.75f), Vector2.zero, Vector2.zero);
		RectTransform val2 = UiUtil.NewRect("Fill Area", (Transform)(object)val);
		UiUtil.Stretch(val2, new Vector2(0f, 0.25f), new Vector2(1f, 0.75f), new Vector2(-20f, 0f), new Vector2(-5f, 0f));
		Image val3 = UiUtil.NewImage("Fill", (Transform)(object)val2, sprite, new Color(0.416f, 0.302f, 0.322f), 10f);
		UiUtil.Stretch(((Graphic)val3).rectTransform, Vector2.zero, new Vector2(0f, 1f), new Vector2(10f, 0f), Vector2.zero);
		RectTransform val4 = UiUtil.NewRect("Handle Slide Area", (Transform)(object)val);
		UiUtil.Stretch(val4, Vector2.zero, Vector2.one, new Vector2(-20f, 0f), Vector2.zero);
		Image val5 = UiUtil.NewImage("Handle", (Transform)(object)val4, sprite, new Color(0.961f, 0.929f, 0.882f), 6f);
		UiUtil.Stretch(((Graphic)val5).rectTransform, Vector2.zero, new Vector2(0f, 1f), new Vector2(22f, 12f), Vector2.zero);
		((Shadow)((Component)val5).gameObject.AddComponent<Outline>()).effectColor = new Color(0.416f, 0.302f, 0.322f);
		Slider obj = ((Component)val).gameObject.AddComponent<Slider>();
		obj.fillRect = ((Graphic)val3).rectTransform;
		obj.handleRect = ((Graphic)val5).rectTransform;
		((Selectable)obj).targetGraphic = (Graphic)(object)val5;
		return obj;
	}

	private static Button BuildButton(Transform parent, Sprite sprite)
	{
		//IL_0016: 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_0078: Unknown result type (might be due to invalid IL or missing references)
		Image val = UiUtil.NewImage("Button", parent, sprite, new Color(0.906f, 0.663f, 0.4f), 7.2f);
		Button obj = ((Component)val).gameObject.AddComponent<Button>();
		((Selectable)obj).targetGraphic = (Graphic)(object)val;
		((Graphic)UiUtil.NewImage("Image_Icon", ((Component)val).transform, null, new Color(0.961f, 0.929f, 0.882f), 1f)).raycastTarget = false;
		((Graphic)val).rectTransform.sizeDelta = new Vector2(65f, 65f);
		return obj;
	}
}
internal sealed class VoiceTab : MonoBehaviour
{
	private const float SelectedHeight = 107.2f;

	private const float UnselectedHeight = 97.2f;

	private const float TweenTime = 0.2f;

	private const float ListSyncInterval = 0.5f;

	private static readonly Color FallbackSelected = new Color(0.961f, 0.929f, 0.882f);

	private static readonly Color FallbackServer = new Color(0.906f, 0.663f, 0.4f);

	private static readonly Color FallbackBanned = new Color(0.906f, 0.502f, 0.427f);

	private static readonly Color FallbackGreen = new Color(0.702f, 0.82f, 0.498f);

	private static PlayerPanelController _failedFor;

	private PlayerPanelController _players;

	private RectTransform _tabButton;

	private TMP_Text _tabLabel;

	private Transform _background;

	private ScrollRect _scroll;

	private TMP_Text _header;

	private TMP_Text _empty;

	private GameObject _rowPrefab;

	private Slider _sliderTemplate;

	private Sprite _panelSprite;

	private readonly List<VoiceRow> _rows = new List<VoiceRow>();

	private bool _selected;

	private bool _rowsFailed;

	private float _nextSync;

	private string _lastError;

	internal static VoiceTab Current { get; private set; }

	internal PlayerPanelController Panel => _players;

	internal static void EnsureInjected(PlayerPanelController players)
	{
		if ((Object)(object)players == (Object)null || (Object)(object)players == (Object)(object)_failedFor || ((Object)(object)Current != (Object)null && (Object)(object)Current._players == (Object)(object)players))
		{
			return;
		}
		try
		{
			Inject(players);
		}
		catch (Exception ex)
		{
			_failedFor = players;
			Plugin.Log.LogError((object)("Could not add the Voice tab to the player list (volumes still apply): " + ex));
		}
	}

	private static void Inject(PlayerPanelController players)
	{
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cb: Expected O, but got Unknown
		//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00da: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_022e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0235: Expected O, but got Unknown
		//IL_02da: Unknown result type (might be due to invalid IL or missing references)
		GameObject obj = GameRefs.Get<PlayerPanelController, GameObject>(GameRefs.ServerList, players);
		RectTransform val = GameRefs.Get<PlayerPanelController, RectTransform>(GameRefs.ServerButton, players);
		RectTransform val2 = GameRefs.Get<PlayerPanelController, RectTransform>(GameRefs.BannedButton, players);
		GameObject val3 = GameRefs.Get<PlayerPanelController, GameObject>(GameRefs.ItemPrefab, players);
		if ((Object)(object)obj == (Object)null || (Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null)
		{
			throw new InvalidOperationException("the player list layout has changed");
		}
		Transform parent = obj.transform.parent;
		if ((Object)(object)parent == (Object)null || (Object)(object)parent.parent != (Object)(object)((Transform)val2).parent)
		{
			throw new InvalidOperationException("the player list layout has changed");
		}
		Strings.Refresh();
		GameObject val4 = Object.Instantiate<GameObject>(((Component)val2).gameObject, ((Transform)val2).parent, false);
		((Object)val4).name = "Button_Voice";
		UiUtil.RemoveLocalization(val4);
		RectTransform val5 = (RectTransform)val4.transform;
		val5.anchoredPosition = val2.anchoredPosition + (val2.anchoredPosition - val.anchoredPosition);
		((Transform)val5).SetSiblingIndex(parent.GetSiblingIndex());
		GameObject val6 = Object.Instantiate<GameObject>(obj, parent, false);
		((Object)val6).name = "Scrollview_Voice";
		val6.SetActive(false);
		UiUtil.RemoveLocalization(val6);
		ScrollRect component = val6.GetComponent<ScrollRect>();
		if ((Object)(object)component == (Object)null || (Object)(object)component.content == (Object)null)
		{
			Object.Destroy((Object)(object)val4);
			Object.Destroy((Object)(object)val6);
			throw new InvalidOperationException("the Server list has no scroll view");
		}
		RectTransform content = component.content;
		for (int num = ((Transform)content).childCount - 1; num >= 0; num--)
		{
			GameObject gameObject = ((Component)((Transform)content).GetChild(num)).gameObject;
			if ((Object)(object)gameObject.GetComponent<PlayerItemController>() != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)gameObject);
			}
		}
		VoiceTab voiceTab = val6.AddComponent<VoiceTab>();
		voiceTab._players = players;
		voiceTab._tabButton = val5;
		voiceTab._tabLabel = val4.GetComponentInChildren<TMP_Text>(true);
		voiceTab._background = parent;
		voiceTab._scroll = component;
		voiceTab._rowPrefab = val3;
		voiceTab._sliderTemplate = GameRefs.Get<SettingsController, Slider>(GameRefs.SettingsVoiceSlider, MonoSingleton<SettingsController>.I);
		Image component2 = ((Component)parent).GetComponent<Image>();
		voiceTab._panelSprite = (((Object)(object)component2 != (Object)null) ? component2.sprite : null);
		foreach (Transform item in (Transform)content)
		{
			Transform val7 = item;
			voiceTab._header = ((Component)val7).GetComponent<TMP_Text>();
			if ((Object)(object)voiceTab._header != (Object)null)
			{
				break;
			}
		}
		if ((Object)(object)voiceTab._header != (Object)null)
		{
			voiceTab._empty = Object.Instantiate<GameObject>(((Component)voiceTab._header).gameObject, (Transform)(object)content, false).GetComponent<TMP_Text>();
			((Object)voiceTab._empty).name = "Text_NoPlayers";
			voiceTab._empty.fontSize = voiceTab._header.fontSize * 0.85f;
			((Graphic)voiceTab._empty).color = players.IconActiveColor;
			((Component)voiceTab._empty).gameObject.SetActive(false);
		}
		Button component3 = val4.GetComponent<Button>();
		UiUtil.SetOnClick(component3, voiceTab.OnTabClicked);
		UiUtil.DisableNavigation((Selectable)(object)component3);
		voiceTab.RefreshTexts();
		voiceTab.ShowTabAsSelected(selected: false, animate: false);
		Current = voiceTab;
		_failedFor = null;
		Plugin.Log.LogInfo((object)"Added the Voice tab to the player list.");
	}

	private void OnDestroy()
	{
		if ((Object)(object)Current == (Object)(object)this)
		{
			Current = null;
		}
		if ((Object)(object)_tabButton != (Object)null)
		{
			Object.Destroy((Object)(object)((Component)_tabButton).gameObject);
		}
		if ((Object)(object)Plugin.Instance != (Object)null)
		{
			Plugin.Instance.Store.Save();
		}
	}

	private void OnTabClicked()
	{
		if (!_selected)
		{
			GameAccess.PlayUIChange();
			Select();
		}
	}

	private void Select()
	{
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: 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)
		_selected = true;
		if (GameRefs.PanelType != null)
		{
			GameRefs.PanelType.Invoke(_players) = (PlayerPanelType)0;
		}
		GameObject val = GameRefs.Get<PlayerPanelController, GameObject>(GameRefs.ServerList, _players);
		GameObject val2 = GameRefs.Get<PlayerPanelController, GameObject>(GameRefs.BannedList, _players);
		if ((Object)(object)val != (Object)null)
		{
			val.SetActive(false);
		}
		if ((Object)(object)val2 != (Object)null)
		{
			val2.SetActive(false);
		}
		RectTransform val3 = GameRefs.Get<PlayerPanelController, RectTransform>(GameRefs.ServerButton, _players);
		RectTransform val4 = GameRefs.Get<PlayerPanelController, RectTransform>(GameRefs.BannedButton, _players);
		Animate(val3, ColorOf(GameRefs.ServerColor, FallbackServer), 97.2f, animate: true);
		Animate(val4, ColorOf(GameRefs.BannedColor, FallbackBanned), 97.2f, animate: true);
		ShowTabAsSelected(selected: true, animate: true);
		PutInFront(_tabButton, val3, val4);
		((Component)this).gameObject.SetActive(true);
		RefreshTexts();
		SyncRows(force: true);
		LayoutRebuilder.ForceRebuildLayoutImmediate(_scroll.content);
		_scroll.verticalNormalizedPosition = 1f;
	}

	internal void OnGameTabSelected(RectTransform selectedButton)
	{
		bool selected = _selected;
		_selected = false;
		((Component)this).gameObject.SetActive(false);
		ShowTabAsSelected(selected: false, selected);
		RectTransform val = GameRefs.Get<PlayerPanelController, RectTransform>(GameRefs.ServerButton, _players);
		RectTransform val2 = GameRefs.Get<PlayerPanelController, RectTransform>(GameRefs.BannedButton, _players);
		RectTransform val3 = (((Object)(object)selectedButton == (Object)(object)val) ? val2 : val);
		PutInFront(selectedButton, val3, _tabButton);
		if (!selected)
		{
			RefreshTexts();
		}
	}

	private void ShowTabAsSelected(bool selected, bool animate)
	{
		//IL_001b: 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_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		Color color = (selected ? ColorOf(GameRefs.SelectedColor, FallbackSelected) : ColorOf(GameRefs.GreenColor, FallbackGreen));
		Animate(_tabButton, color, selected ? 107.2f : 97.2f, animate);
	}

	private Color ColorOf(FieldRef<PlayerPanelController, Color> field, Color fallback)
	{
		//IL_0011: 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_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		if (field == null || (Object)(object)_players == (Object)null)
		{
			return fallback;
		}
		Color val = field.Invoke(_players);
		if (!(val.a > 0f))
		{
			return fallback;
		}
		return val;
	}

	private static void Animate(RectTransform button, Color color, float height, bool animate)
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0062: 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_004a: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)button == (Object)null)
		{
			return;
		}
		Image component = ((Component)button).GetComponent<Image>();
		Vector2 val = default(Vector2);
		((Vector2)(ref val))..ctor(button.sizeDelta.x, height);
		ShortcutExtensions.DOKill((Component)(object)button, false);
		if ((Object)(object)component != (Object)null)
		{
			ShortcutExtensions.DOKill((Component)(object)component, false);
		}
		if (!animate)
		{
			if ((Object)(object)component != (Object)null)
			{
				((Graphic)component).color = color;
			}
			button.sizeDelta = val;
		}
		else
		{
			if ((Object)(object)component != (Object)null)
			{
				DOTweenModuleUI.DOColor(component, color, 0.2f);
			}
			DOTweenModuleUI.DOSizeDelta(button, val, 0.2f, false);
		}
	}

	private void PutInFront(RectTransform selected, params RectTransform[] others)
	{
		if ((Object)(object)_background == (Object)null)
		{
			return;
		}
		foreach (RectTransform val in others)
		{
			if ((Object)(object)val != (Object)null && (Object)(object)((Transform)val).parent == (Object)(object)_background.parent && ((Transform)val).GetSiblingIndex() > _background.GetSiblingIndex())
			{
				((Transform)val).SetSiblingIndex(_background.GetSiblingIndex());
			}
		}
		if ((Object)(object)selected != (Object)null && (Object)(object)((Transform)selected).parent == (Object)(object)_background.parent && ((Transform)selected).GetSiblingIndex() < _background.GetSiblingIndex())
		{
			((Transform)selected).SetSiblingIndex(_background.GetSiblingIndex());
		}
	}

	private void RefreshTexts()
	{
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		Strings.Refresh();
		if ((Object)(object)_tabLabel != (Object)null)
		{
			_tabLabel.text = Strings.Tab;
		}
		if ((Object)(object)_header != (Object)null)
		{
			_header.text = Strings.Header + "  <size=70%><color=#" + ColorUtility.ToHtmlStringRGB(_players.IconActiveColor) + ">· " + Strings.Hint + "</color></size>";
		}
		if ((Object)(object)_empty != (Object)null)
		{
			_empty.text = Strings.NoPlayers;
		}
	}

	internal void RefreshVolumes()
	{
		if (_selected)
		{
			SyncRows(force: true);
		}
	}

	internal void MarkPlayersChanged()
	{
		_nextSync = 0f;
	}

	private void Update()
	{
		try
		{
			if (Time.unscaledTime >= _nextSync)
			{
				SyncRows(force: false);
			}
			for (int i = 0; i < _rows.Count; i++)
			{
				VoiceRow voiceRow = _rows[i];
				if ((Object)(object)voiceRow != (Object)null && ((Component)voiceRow).gameObject.activeSelf)
				{
					voiceRow.RefreshStatus();
				}
			}
		}
		catch (Exception ex)
		{
			string text = ex.GetType().Name + ": " + ex.Message;
			if (text != _lastError)
			{
				_lastError = text;
				Plugin.Log.LogError((object)("Voice tab update failed: " + ex));
			}
		}
	}

	private void SyncRows(bool force)
	{
		_nextSync = Time.unscaledTime + 0.5f;
		PlayerPanelController players = _players;
		if ((Object)(object)players == (Object)null || players.PlayerSteamIDs == null)
		{
			return;
		}
		int num = 0;
		for (int i = 0; i < players.PlayerSteamIDs.Count; i++)
		{
			string text = players.PlayerSteamIDs[i];
			if (!string.IsNullOrEmpty(text) && !GameAccess.IsLocalPlayer(players, i))
			{
				VoiceRow voiceRow = ((num < _rows.Count) ? _rows[num] : AddRow());
				if ((Object)(object)voiceRow == (Object)null)
				{
					break;
				}
				if (!((Component)voiceRow).gameObject.activeSelf)
				{
					((Component)voiceRow).gameObject.SetActive(true);
				}
				voiceRow.Bind(text, GameAccess.RawPlayerName(players, i), force);
				num++;
			}
		}
		for (int j = num; j < _rows.Count; j++)
		{
			if ((Object)(object)_rows[j] != (Object)null && ((Component)_rows[j]).gameObject.activeSelf)
			{
				((Component)_rows[j]).gameObject.SetActive(false);
			}
		}
		if ((Object)(object)_empty != (Object)null && ((Component)_empty).gameObject.activeSelf != (num == 0))
		{
			((Component)_empty).gameObject.SetActive(num == 0);
		}
	}

	private VoiceRow AddRow()
	{
		if (_rowsFailed)
		{
			return null;
		}
		try
		{
			VoiceRow voiceRow = VoiceRow.Create(this, _rowPrefab, (Transform)(object)_scroll.content, _sliderTemplate, _panelSprite);
			_rows.Add(voiceRow);
			return voiceRow;
		}
		catch (Exception ex)
		{
			_rowsFailed = true;
			Plugin.Log.LogError((object)("Could not create a player row in the Voice tab: " + ex));
			return null;
		}
	}

	internal void ShowInfo(RectTransform anchor, string title, string text)
	{
		//IL_0082: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
		RectTransform val = GameRefs.Get<PlayerPanelController, RectTransform>(GameRefs.InfoPanel, _players);
		CanvasGroup val2 = GameRefs.Get<PlayerPanelController, CanvasGroup>(GameRefs.InfoGroup, _players);
		if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null) && !((Object)(object)anchor == (Object)null))
		{
			Image val3 = GameRefs.Get<PlayerPanelController, Image>(GameRefs.InfoHeaderBg, _players);
			TextMeshProUGUI val4 = GameRefs.Get<PlayerPanelController, TextMeshProUGUI>(GameRefs.InfoHeader, _players);
			TextMeshProUGUI val5 = GameRefs.Get<PlayerPanelController, TextMeshProUGUI>(GameRefs.InfoText, _players);
			if ((Object)(object)val3 != (Object)null)
			{
				((Graphic)val3).color = ColorOf(GameRefs.OrangeColor, FallbackServer);
			}
			if ((Object)(object)val4 != (Object)null)
			{
				((TMP_Text)val4).text = title;
			}
			if ((Object)(object)val5 != (Object)null)
			{
				((TMP_Text)val5).text = text;
			}
			((Transform)val).position = ((Transform)anchor).position;
			DOTweenModuleUI.DOFade(val2, 1f, 0.15f);
		}
	}
}
internal static class VolumeMath
{
	public const int VivoxMute = -50;

	public const int VivoxMax = 50;

	public static int ToVivox(int percent)
	{
		if (percent <= 0)
		{
			return -50;
		}
		return Mathf.Clamp((int)Math.Round(10.0 * Math.Log((double)percent / 100.0, 2.0)), -49, 50);
	}

	public static string Format(int percent)
	{
		return "%" + percent;
	}
}
[Serializable]
internal sealed class SavedVolume
{
	public string steamId;

	public string name;

	public int volume;
}
[Serializable]
internal sealed class SavedVolumes
{
	public int version = 1;

	public List<SavedVolume> players = new List<SavedVolume>();
}
internal sealed class VolumeStore
{
	private const float SaveDelay = 2f;

	private const int MaxPercent = 400;

	private readonly string _path;

	private readonly Dictionary<string, SavedVolume> _byId = new Dictionary<string, SavedVolume>(StringComparer.Ordinal);

	private bool _dirty;

	private float _saveAt;

	public int Count => _byId.Count;

	public VolumeStore(string path)
	{
		_path = path;
	}

	public bool TryGet(string steamId, out int percent)
	{
		if (!string.IsNullOrEmpty(steamId) && _byId.TryGetValue(steamId, out var value))
		{
			percent = value.volume;
			return true;
		}
		percent = 0;
		return false;
	}

	public void Set(string steamId, string name, int percent)
	{
		if (!string.IsNullOrEmpty(steamId))
		{
			percent = Mathf.Clamp(percent, 0, 400);
			if (!_byId.TryGetValue(steamId, out var value))
			{
				value = new SavedVolume
				{
					steamId = steamId,
					volume = percent
				};
				_byId[steamId] = value;
				MarkDirty();
			}
			else if (value.volume != percent)
			{
				value.volume = percent;
				MarkDirty();
			}
			if (!string.IsNullOrEmpty(name) && value.name != name)
			{
				value.name = name;
				MarkDirty();
			}
		}
	}

	public void Remove(string steamId)
	{
		if (!string.IsNullOrEmpty(steamId) && _byId.Remove(steamId))
		{
			MarkDirty();
		}
	}

	public void RememberName(string steamId, string name)
	{
		if (!string.IsNullOrEmpty(steamId) && !string.IsNullOrEmpty(name) && _byId.TryGetValue(steamId, out var value) && value.name != name)
		{
			value.name = name;
			MarkDirty();
		}
	}

	private void MarkDirty()
	{
		_dirty = true;
		_saveAt = Time.unscaledTime + 2f;
	}

	public void SaveIfDue()
	{
		if (_dirty && Time.unscaledTime >= _saveAt)
		{
			Save();
		}
	}

	public void Load()
	{
		_byId.Clear();
		if (!File.Exists(_path))
		{
			return;
		}
		try
		{
			SavedVolumes savedVolumes = JsonUtility.FromJson<SavedVolumes>(File.ReadAllText(_path, Encoding.UTF8));
			if (savedVolumes == null || savedVolumes.players == null)
			{
				return;
			}
			foreach (SavedVolume player in savedVolumes.players)
			{
				if (player != null && !string.IsNullOrEmpty(player.steamId))
				{
					player.volume = Mathf.Clamp(player.volume, 0, 400);
					_byId[player.steamId] = player;
				}
			}
		}
		catch (Exception ex)
		{
			string text = _path + ".bad";
			Plugin.Log.LogError((object)("Could not read " + _path + ": " + ex.Message + ". A copy was kept as " + text + "."));
			try
			{
				File.Copy(_path, text, overwrite: true);
			}
			catch (Exception ex2)
			{
				Plugin.Log.LogWarning((object)("Could not back up the file: " + ex2.Message));
			}
		}
	}

	public void Save()
	{
		if (!_dirty)
		{
			return;
		}
		_dirty = false;
		try
		{
			SavedVolumes savedVolumes = new SavedVolumes
			{
				players = _byId.Values.OrderBy<SavedVolume, string>((SavedVolume e) => e.name ?? e.steamId, StringComparer.OrdinalIgnoreCase).ToList()
			};
			string text = _path + ".tmp";
			File.WriteAllText(text, JsonUtility.ToJson((object)savedVolumes, true), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
			File.Copy(text, _path, overwrite: true);
			File.Delete(text);
		}
		catch (Exception ex)
		{
			Plugin.Log.LogError((object)("Could not save player volumes to " + _path + ": " + ex.Message));
		}
	}
}