Decompiled source of BetterPeakVoiceFix EnFork v0.3.4

BetterVoiceFixEn.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using PeakVoiceFix.Patches;
using Photon.Pun;
using Photon.Realtime;
using Photon.Voice.PUN;
using Photon.Voice.Unity;
using Steamworks;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("BetterVoiceFixEn")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("0.3.4.0")]
[assembly: AssemblyInformationalVersion("0.3.4+b9d50247aac75a154ab2a0394fdfc76e45d36004")]
[assembly: AssemblyProduct("BetterVoiceFixEn")]
[assembly: AssemblyTitle("BetterVoiceFixEn")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.3.4.0")]
[module: UnverifiableCode]
namespace PeakVoiceFix
{
	public class CacheEntry
	{
		public string IP;

		public float LastSeenTime;

		public string PlayerName;

		public byte RemoteState;

		public string ModVersion;
	}
	public class SOSData
	{
		public int ActorNumber;

		public string PlayerName;

		public string TargetIP;

		public string OriginIP;

		public float ReceiveTime;
	}
	public static class NetworkManager
	{
		public static Dictionary<int, CacheEntry> PlayerCache = new Dictionary<int, CacheEntry>();

		public static List<SOSData> ActiveSOSList = new List<SOSData>();

		public static List<string> HostHistory = new List<string>();

		private static string LastKnownHostIP = "";

		private static string LastDecisionLog = "";

		private static ClientState lastClientState = (ClientState)14;

		public static PunVoiceClient punVoice;

		private static float nextRetryTime = 0f;

		private static float lastPingPublishTime = 0f;

		private static float lastSOSTime = 0f;

		private static float nextSummaryLogTime = 0f;

		private const float SCAN_INTERVAL = 30f;

		private const float CACHE_TTL = 180f;

		private const float PING_PUBLISH_INTERVAL = 89f;

		private const string PROP_IP = "PVF_IP";

		private const string PROP_PING = "PVF_Ping";

		private const byte TYPE_SOS = 0;

		private const byte TYPE_LOG = 1;

		private const byte TYPE_STATE = 2;

		public static string TargetGameServer { get; private set; }

		public static bool ConnectedUsingHost { get; private set; } = true;


		public static bool IsBlindConnect { get; private set; } = false;


		public static int WrongIPCount { get; private set; } = 0;


		public static int ConnectionFailCount { get; private set; } = 0;


		public static int TotalRetryCount { get; private set; } = 0;


		public static string LastErrorMessage { get; private set; } = "";


		public static float LastScanTime { get; private set; } = 0f;


		public static float LastHostUpdateTime { get; private set; } = 0f;


		public static string GetPlayerName(int actorNumber)
		{
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			string text = "Unknown";
			Player val = null;
			if (PhotonNetwork.CurrentRoom != null)
			{
				val = PhotonNetwork.CurrentRoom.GetPlayer(actorNumber, false);
			}
			if (val != null && !string.IsNullOrEmpty(val.NickName))
			{
				text = val.NickName;
				UpdatePlayerCache(actorNumber, text);
				return text;
			}
			if (PlayerCache.ContainsKey(actorNumber))
			{
				string playerName = PlayerCache[actorNumber].PlayerName;
				if (!string.IsNullOrEmpty(playerName) && playerName != "Unknown" && !playerName.StartsWith("Player "))
				{
					return playerName;
				}
			}
			if ((text == "Unknown" || string.IsNullOrEmpty(text)) && val != null && !string.IsNullOrEmpty(val.UserId))
			{
				try
				{
					if (ulong.TryParse(val.UserId, out var result))
					{
						string friendPersonaName = SteamFriends.GetFriendPersonaName(new CSteamID(result));
						if (!string.IsNullOrEmpty(friendPersonaName) && friendPersonaName != "[unknown]")
						{
							text = friendPersonaName;
							UpdatePlayerCache(actorNumber, text);
							return text;
						}
					}
				}
				catch (Exception)
				{
				}
			}
			if (text == "Unknown" || string.IsNullOrEmpty(text))
			{
				string text2 = ScavengeNameFromScene(actorNumber);
				if (!string.IsNullOrEmpty(text2))
				{
					UpdatePlayerCache(actorNumber, text2);
					return text2;
				}
			}
			if (text == "Unknown")
			{
				return $"Player {actorNumber}";
			}
			return text;
		}

		public static string ScavengeNameFromScene(int actorNumber)
		{
			try
			{
				PhotonView[] array = Object.FindObjectsOfType<PhotonView>();
				PhotonView[] array2 = array;
				foreach (PhotonView val in array2)
				{
					if (!((Object)(object)val == (Object)null) && val.OwnerActorNr == actorNumber)
					{
						if (val.Owner != null && !string.IsNullOrEmpty(val.Owner.NickName))
						{
							return val.Owner.NickName;
						}
						TextMeshProUGUI componentInChildren = ((Component)val).GetComponentInChildren<TextMeshProUGUI>(true);
						if ((Object)(object)componentInChildren != (Object)null && !string.IsNullOrEmpty(((TMP_Text)componentInChildren).text))
						{
							return ((TMP_Text)componentInChildren).text;
						}
						TextMeshPro componentInChildren2 = ((Component)val).GetComponentInChildren<TextMeshPro>(true);
						if ((Object)(object)componentInChildren2 != (Object)null && !string.IsNullOrEmpty(((TMP_Text)componentInChildren2).text))
						{
							return ((TMP_Text)componentInChildren2).text;
						}
						Text componentInChildren3 = ((Component)val).GetComponentInChildren<Text>(true);
						if ((Object)(object)componentInChildren3 != (Object)null && !string.IsNullOrEmpty(componentInChildren3.text))
						{
							return componentInChildren3.text;
						}
					}
				}
			}
			catch (Exception)
			{
			}
			return null;
		}

		public static void UpdatePlayerCache(int actorNumber, string name, string ip = null, string version = null)
		{
			if (!PlayerCache.ContainsKey(actorNumber))
			{
				PlayerCache[actorNumber] = new CacheEntry();
			}
			if (!string.IsNullOrEmpty(name) && name != "Unknown")
			{
				PlayerCache[actorNumber].PlayerName = name;
			}
			if (!string.IsNullOrEmpty(ip))
			{
				PlayerCache[actorNumber].IP = ip;
			}
			if (!string.IsNullOrEmpty(version))
			{
				PlayerCache[actorNumber].ModVersion = version;
			}
			PlayerCache[actorNumber].LastSeenTime = Time.unscaledTime;
		}

		public static bool IsGhost(int actorNumber)
		{
			if (PhotonNetwork.CurrentRoom == null)
			{
				return true;
			}
			return PhotonNetwork.CurrentRoom.GetPlayer(actorNumber, false) == null;
		}

		public static int GetGhostCount()
		{
			if ((Object)(object)punVoice == (Object)null || ((VoiceConnection)punVoice).Client == null || ((LoadBalancingClient)((VoiceConnection)punVoice).Client).CurrentRoom == null)
			{
				return 0;
			}
			int num = 0;
			foreach (int key in ((LoadBalancingClient)((VoiceConnection)punVoice).Client).CurrentRoom.Players.Keys)
			{
				if (IsGhost(key))
				{
					num++;
				}
			}
			return num;
		}

		public static void SystemUpdate()
		{
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: 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_00bd: Invalid comparison between Unknown and I4
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)punVoice == (Object)null)
			{
				GameObject val = GameObject.Find("VoiceClient");
				if ((Object)(object)val != (Object)null)
				{
					punVoice = val.GetComponent<PunVoiceClient>();
				}
			}
			if (!PhotonNetwork.InRoom)
			{
				return;
			}
			if ((Object)(object)punVoice != (Object)null && ((VoiceConnection)punVoice).Client != null)
			{
				ClientState state = ((LoadBalancingClient)((VoiceConnection)punVoice).Client).State;
				if (state != lastClientState)
				{
					string message = $"State Change: {lastClientState} -> {state}";
					BroadcastLog(message);
					SendStateSync(state);
					if ((int)state == 9)
					{
						ConnectionFailCount = 0;
					}
					UpdateDataLayer(force: true);
					lastClientState = state;
				}
			}
			UpdateDataLayer();
			HandleInputAndState();
			ManageSOSList();
			if ((Object)(object)punVoice != (Object)null && ((VoiceConnection)punVoice).Client != null && Time.unscaledTime >= nextRetryTime)
			{
				if (PhotonNetwork.IsMasterClient)
				{
					HandleHostLogic();
				}
				else
				{
					HandleClientLogic();
				}
			}
		}

		public static void SendStateSync(ClientState state)
		{
			//IL_0001: 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_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			byte b = (byte)state;
			object[] array = new object[3]
			{
				(byte)2,
				b,
				"v0.3.4 (EN)"
			};
			RaiseEventOptions val = new RaiseEventOptions
			{
				Receivers = (ReceiverGroup)0
			};
			PhotonNetwork.RaiseEvent((byte)186, (object)array, val, SendOptions.SendUnreliable);
		}

		public static void BroadcastLog(string message)
		{
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			if (VoiceFix.EnableDebugLogs != null && VoiceFix.EnableDebugLogs.Value)
			{
				VoiceFix.logger.LogInfo((object)message);
			}
			string playerName = GetPlayerName(PhotonNetwork.LocalPlayer.ActorNumber);
			if ((Object)(object)VoiceUIManager.Instance != (Object)null)
			{
				VoiceUIManager.Instance.AddLog(playerName, message, isLocal: true);
			}
			byte b = 186;
			object[] array = new object[2]
			{
				(byte)1,
				message
			};
			RaiseEventOptions val = new RaiseEventOptions
			{
				Receivers = (ReceiverGroup)0
			};
			PhotonNetwork.RaiseEvent(b, (object)array, val, SendOptions.SendReliable);
		}

		private static void UpdateDataLayer(bool force = false)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Invalid comparison between Unknown and I4
			bool flag = Time.unscaledTime - lastPingPublishTime > 89f;
			if ((force || flag) && (Object)(object)punVoice != (Object)null && ((VoiceConnection)punVoice).Client != null)
			{
				lastPingPublishTime = Time.unscaledTime;
				Hashtable val = new Hashtable();
				val[(object)"PVF_Ping"] = PhotonNetwork.GetPing();
				string ip = (string)(val[(object)"PVF_IP"] = (((int)((LoadBalancingClient)((VoiceConnection)punVoice).Client).State == 9) ? ((LoadBalancingClient)((VoiceConnection)punVoice).Client).GameServerAddress : ""));
				PhotonNetwork.LocalPlayer.SetCustomProperties(val, (Hashtable)null, (WebFlags)null);
				UpdatePlayerCache(PhotonNetwork.LocalPlayer.ActorNumber, PhotonNetwork.LocalPlayer.NickName, ip, "v0.3.4 (EN)");
			}
			if (!force)
			{
				if (Time.unscaledTime - LastScanTime > 30f)
				{
					LastScanTime = Time.unscaledTime;
					ScanPlayers();
				}
				if (Time.unscaledTime > nextSummaryLogTime)
				{
					PrintSummaryLog();
					nextSummaryLogTime = Time.unscaledTime + 60f;
				}
			}
		}

		private static void PrintSummaryLog()
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine($"[Cache Dump] Count:{PlayerCache.Count}");
			foreach (KeyValuePair<int, CacheEntry> item in PlayerCache)
			{
				string arg = (string.IsNullOrEmpty(item.Value.IP) ? "N/A" : item.Value.IP);
				stringBuilder.AppendLine($" - {item.Value.PlayerName}: {arg} (St:{item.Value.RemoteState})");
			}
			if ((Object)(object)VoiceUIManager.Instance != (Object)null)
			{
				VoiceUIManager.Instance.AddLog("System", stringBuilder.ToString(), isLocal: true);
			}
		}

		private static void ScanPlayers()
		{
			Player[] playerListOthers = PhotonNetwork.PlayerListOthers;
			foreach (Player val in playerListOthers)
			{
				object value = null;
				if (!((Dictionary<object, object>)(object)val.CustomProperties).TryGetValue((object)"PVF_IP", out value) || !(value is string text))
				{
					continue;
				}
				string playerName = GetPlayerName(val.ActorNumber);
				UpdatePlayerCache(val.ActorNumber, playerName, text);
				if (!val.IsMasterClient)
				{
					continue;
				}
				if (!string.IsNullOrEmpty(text))
				{
					LastHostUpdateTime = Time.unscaledTime;
				}
				if (!string.IsNullOrEmpty(LastKnownHostIP) && LastKnownHostIP != text && !string.IsNullOrEmpty(text))
				{
					string message = "Host IP Changed: " + LastKnownHostIP + " -> " + text;
					BroadcastLog(message);
					if (HostHistory.Count > 5)
					{
						HostHistory.RemoveAt(0);
					}
					HostHistory.Add($"[{DateTime.Now:HH:mm:ss}] {text}");
				}
				LastKnownHostIP = text;
			}
			List<int> list = (from x in PlayerCache
				where Time.unscaledTime - x.Value.LastSeenTime > 180f
				select x.Key).ToList();
			foreach (int item in list)
			{
				PlayerCache.Remove(item);
			}
		}

		private static void ManageSOSList()
		{
			for (int num = ActiveSOSList.Count - 1; num >= 0; num--)
			{
				SOSData sOSData = ActiveSOSList[num];
				if (Time.unscaledTime - sOSData.ReceiveTime > 60f)
				{
					ActiveSOSList.RemoveAt(num);
				}
				else if (GetPlayerName(sOSData.ActorNumber) == "Unknown")
				{
					ActiveSOSList.RemoveAt(num);
				}
				else
				{
					Player player = PhotonNetwork.CurrentRoom.GetPlayer(sOSData.ActorNumber, false);
					object value = null;
					if (player != null && ((Dictionary<object, object>)(object)player.CustomProperties).TryGetValue((object)"PVF_IP", out value) && value is string value2 && !string.IsNullOrEmpty(value2))
					{
						ActiveSOSList.RemoveAt(num);
					}
				}
			}
		}

		private static void HandleHostLogic()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Invalid comparison between Unknown and I4
			if ((int)((LoadBalancingClient)((VoiceConnection)punVoice).Client).State == 14)
			{
				BroadcastLog("[Host] Unexpected disconnect, auto recovering...");
				((VoiceConnection)punVoice).ConnectUsingSettings(PhotonNetwork.PhotonServerSettings.AppSettings);
				nextRetryTime = Time.unscaledTime + 5f;
			}
		}

		private static void HandleClientLogic()
		{
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Invalid comparison between Unknown and I4
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Invalid comparison between Unknown and I4
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Invalid comparison between Unknown and I4
			string mode;
			string text = DecideTargetIP(out mode);
			if (!string.IsNullOrEmpty(text) && ConnectionFailCount > 0 && ConnectionFailCount % 6 >= 3)
			{
				BroadcastLog($"[Loop] Failed {ConnectionFailCount} times, switching to Blind...");
				text = null;
				mode += "->BlindLoop";
			}
			if (string.IsNullOrEmpty(text))
			{
				IsBlindConnect = true;
				TargetGameServer = null;
				if ((int)((LoadBalancingClient)((VoiceConnection)punVoice).Client).State == 14)
				{
					PerformReconnect("Blind");
				}
				return;
			}
			IsBlindConnect = false;
			TargetGameServer = text;
			string gameServerAddress = ((LoadBalancingClient)((VoiceConnection)punVoice).Client).GameServerAddress;
			ClientState state = ((LoadBalancingClient)((VoiceConnection)punVoice).Client).State;
			if ((int)state == 9)
			{
				if (gameServerAddress == TargetGameServer)
				{
					WrongIPCount = 0;
					ConnectionFailCount = 0;
					TotalRetryCount = 0;
					return;
				}
				WrongIPCount++;
				if (WrongIPCount <= 2)
				{
					BroadcastLog($"[Mismatch] Cur:{gameServerAddress} Tgt:{TargetGameServer} | Correction({WrongIPCount}/2)");
					((LoadBalancingClient)((VoiceConnection)punVoice).Client).Disconnect();
					PerformReconnect(mode);
				}
				else if (WrongIPCount == 3)
				{
					BroadcastLog("[GiveUp] Correction failed, staying on: " + gameServerAddress);
				}
			}
			else if ((int)state == 14)
			{
				ConnectionFailCount++;
				PerformReconnect(mode);
			}
		}

		private static void SetGameServerAddress(LoadBalancingClient client, string ip)
		{
			try
			{
				BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
				PropertyInfo property = ((object)client).GetType().GetProperty("GameServerAddress", bindingAttr);
				if (property != null && property.CanWrite)
				{
					property.SetValue(client, ip);
					return;
				}
				Type type = ((object)client).GetType();
				while (type != null)
				{
					FieldInfo field = type.GetField("GameServerAddress", bindingAttr);
					if (field == null)
					{
						field = type.GetField("<GameServerAddress>k__BackingField", bindingAttr);
					}
					if (field != null)
					{
						field.SetValue(client, ip);
						return;
					}
					type = type.BaseType;
				}
				if (VoiceFix.logger != null)
				{
					VoiceFix.logger.LogError((object)"Reflection failed for IP");
				}
			}
			catch (Exception arg)
			{
				if (VoiceFix.logger != null)
				{
					VoiceFix.logger.LogError((object)$"Reflection Error: {arg}");
				}
			}
		}

		private static string DecideTargetIP(out string mode)
		{
			int maxCount;
			string majorityIP = GetMajorityIP(out maxCount);
			if (!string.IsNullOrEmpty(majorityIP) && maxCount >= 2)
			{
				mode = $"Majority({maxCount})";
				ConnectedUsingHost = false;
				LogDecision(mode, majorityIP);
				return majorityIP;
			}
			if (!string.IsNullOrEmpty(LastKnownHostIP))
			{
				mode = "Host";
				ConnectedUsingHost = true;
				LogDecision(mode, LastKnownHostIP);
				return LastKnownHostIP;
			}
			mode = "Auto(Blind)";
			ConnectedUsingHost = false;
			LogDecision(mode, "Auto");
			return null;
		}

		private static void LogDecision(string mode, string target)
		{
			string text = mode + "->" + target;
			if (text != LastDecisionLog)
			{
				BroadcastLog("[Decision] Target: " + text);
				LastDecisionLog = text;
			}
		}

		public static string GetMajorityIP(out int maxCount)
		{
			maxCount = 0;
			if (PlayerCache.Count == 0)
			{
				return null;
			}
			Dictionary<string, int> dictionary = new Dictionary<string, int>();
			foreach (KeyValuePair<int, CacheEntry> item in PlayerCache)
			{
				if (!string.IsNullOrEmpty(item.Value.IP))
				{
					if (!dictionary.ContainsKey(item.Value.IP))
					{
						dictionary[item.Value.IP] = 0;
					}
					dictionary[item.Value.IP]++;
				}
			}
			string result = null;
			foreach (KeyValuePair<string, int> item2 in dictionary)
			{
				if (item2.Value > maxCount)
				{
					maxCount = item2.Value;
					result = item2.Key;
				}
			}
			return result;
		}

		private static void PerformReconnect(string mode)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Invalid comparison between Unknown and I4
			TotalRetryCount++;
			nextRetryTime = Time.unscaledTime + VoiceFix.RetryInterval.Value;
			if (Time.unscaledTime - lastSOSTime > 20f && PhotonNetwork.IsConnectedAndReady)
			{
				lastSOSTime = Time.unscaledTime;
				SendSOS(string.IsNullOrEmpty(TargetGameServer) ? "Unknown" : TargetGameServer);
			}
			if ((int)((LoadBalancingClient)((VoiceConnection)punVoice).Client).State != 14)
			{
				((LoadBalancingClient)((VoiceConnection)punVoice).Client).Disconnect();
			}
			SetGameServerAddress((LoadBalancingClient)(object)((VoiceConnection)punVoice).Client, TargetGameServer);
			((VoiceConnection)punVoice).ConnectUsingSettings(PhotonNetwork.PhotonServerSettings.AppSettings);
		}

		private static void SendSOS(string targetInfo)
		{
			//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_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			string text = "Unknown";
			if ((Object)(object)punVoice != (Object)null && ((VoiceConnection)punVoice).Client != null)
			{
				text = ((LoadBalancingClient)((VoiceConnection)punVoice).Client).GameServerAddress;
			}
			if (string.IsNullOrEmpty(text))
			{
				text = "Disconnected";
			}
			BroadcastLog("[SOS] Requesting Help -> Tgt:" + targetInfo + " | Self:" + text);
			object[] array = new object[3]
			{
				(byte)0,
				targetInfo,
				text
			};
			RaiseEventOptions val = new RaiseEventOptions
			{
				Receivers = (ReceiverGroup)0
			};
			PhotonNetwork.RaiseEvent((byte)186, (object)array, val, SendOptions.SendReliable);
		}

		public static void OnEvent(EventData photonEvent)
		{
			if (photonEvent.Code != 186)
			{
				return;
			}
			int senderActor = photonEvent.Sender;
			string playerName = GetPlayerName(senderActor);
			if (!(photonEvent.CustomData is object[] array) || array.Length < 2)
			{
				return;
			}
			byte b = 0;
			if (array[0] is byte b2)
			{
				b = b2;
			}
			else if (array[0] is int num)
			{
				b = (byte)num;
			}
			switch (b)
			{
			case 1:
			{
				string msg = array[1] as string;
				if ((Object)(object)VoiceUIManager.Instance != (Object)null)
				{
					VoiceUIManager.Instance.AddLog(playerName, msg, isLocal: false);
				}
				break;
			}
			case 0:
			{
				string text3 = array[1] as string;
				string originIP = "Unknown(Old)";
				if (array.Length >= 3 && array[2] is string text4)
				{
					originIP = text4;
				}
				else if (PlayerCache.ContainsKey(senderActor))
				{
					originIP = PlayerCache[senderActor].IP;
				}
				ActiveSOSList.RemoveAll((SOSData x) => x.ActorNumber == senderActor);
				ActiveSOSList.Add(new SOSData
				{
					ActorNumber = senderActor,
					PlayerName = playerName,
					TargetIP = text3,
					OriginIP = originIP,
					ReceiveTime = Time.unscaledTime
				});
				if ((Object)(object)VoiceUIManager.Instance != (Object)null)
				{
					VoiceUIManager.Instance.AddLog("System", "SOS from " + playerName + " (Tgt:" + text3 + ")", isLocal: true);
					VoiceUIManager.Instance.TriggerNotification(playerName);
				}
				break;
			}
			case 2:
			{
				byte remoteState = 0;
				if (array[1] is byte b3)
				{
					remoteState = b3;
				}
				else if (array[1] is int num2)
				{
					remoteState = (byte)num2;
				}
				string text = "";
				if (array.Length >= 3 && array[2] is string text2)
				{
					text = text2;
				}
				if (PlayerCache.ContainsKey(senderActor))
				{
					PlayerCache[senderActor].RemoteState = remoteState;
					if (!string.IsNullOrEmpty(text))
					{
						PlayerCache[senderActor].ModVersion = text;
					}
					PlayerCache[senderActor].LastSeenTime = Time.unscaledTime;
				}
				else
				{
					CacheEntry value = new CacheEntry
					{
						PlayerName = playerName,
						LastSeenTime = Time.unscaledTime,
						RemoteState = remoteState,
						ModVersion = text
					};
					PlayerCache[senderActor] = value;
				}
				break;
			}
			}
		}

		private static void HandleInputAndState()
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Invalid comparison between Unknown and I4
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Invalid comparison between Unknown and I4
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Invalid comparison between Unknown and I4
			if (VoiceFix.EnableManualReconnect == null || !VoiceFix.EnableManualReconnect.Value || (!Input.GetKey((KeyCode)308) && !Input.GetKey((KeyCode)307)) || !Input.GetKeyDown((KeyCode)107))
			{
				return;
			}
			if ((int)((LoadBalancingClient)((VoiceConnection)punVoice).Client).State == 9 || (int)((LoadBalancingClient)((VoiceConnection)punVoice).Client).State == 6 || (int)((LoadBalancingClient)((VoiceConnection)punVoice).Client).State == 1)
			{
				BroadcastLog("[System] Alt+K Manual Disconnect");
				if (PhotonNetwork.IsConnectedAndReady)
				{
					SendSOS("Manual Disconnect");
				}
				((LoadBalancingClient)((VoiceConnection)punVoice).Client).Disconnect();
				if ((Object)(object)VoiceUIManager.Instance != (Object)null)
				{
					VoiceUIManager.Instance.ShowStatsTemporary();
				}
			}
			else
			{
				BroadcastLog("[System] Alt+K Force Reconnect");
				if (PhotonNetwork.IsMasterClient)
				{
					int maxCount;
					string majorityIP = GetMajorityIP(out maxCount);
					string ip = ((!string.IsNullOrEmpty(majorityIP) && maxCount >= 2) ? majorityIP : null);
					SetGameServerAddress((LoadBalancingClient)(object)((VoiceConnection)punVoice).Client, ip);
				}
				string targetGameServer = TargetGameServer;
				if (string.IsNullOrEmpty(targetGameServer))
				{
					targetGameServer = "Auto/Blind";
				}
				nextRetryTime = Time.unscaledTime;
				ConnectionFailCount = 0;
				((VoiceConnection)punVoice).ConnectUsingSettings(PhotonNetwork.PhotonServerSettings.AppSettings);
			}
			WrongIPCount = 0;
			TotalRetryCount = 0;
		}
	}
	[HarmonyPatch]
	public static class PhotonRPCFix
	{
		[HarmonyPatch(typeof(PhotonNetwork), "RPC", new Type[]
		{
			typeof(PhotonView),
			typeof(string),
			typeof(RpcTarget),
			typeof(Player),
			typeof(bool),
			typeof(object[])
		})]
		[HarmonyPrefix]
		public static void PrePhotonNetworkRPC(PhotonView view, string methodName, ref RpcTarget target)
		{
			if (VoiceFix.EnableDebugLogs != null && VoiceFix.EnableDebugLogs.Value && !methodName.Contains("Transform") && !methodName.Contains("Movement") && !methodName.Contains("Time") && !methodName.Contains("Speak") && VoiceFix.logger != null)
			{
				VoiceFix.logger.LogWarning((object)$"[RPC Catch] Name: {methodName} | Target: {target}");
			}
		}
	}
	[BepInPlugin("chuxiaaaa.Aiae.BetterVoiceFix", "BetterVoiceFix (EN)", "0.3.4")]
	public class VoiceFix : BaseUnityPlugin
	{
		public static VoiceFix Instance;

		public static ManualLogSource logger;

		public static ManualLogSource debugLogger;

		public static ConfigEntry<string> UIPositionSide;

		public static ConfigEntry<KeyCode> ToggleUIKey;

		public static ConfigEntry<bool> ShowProfessionalInfo;

		public static ConfigEntry<float> OffsetX_Right;

		public static ConfigEntry<float> OffsetY_Right;

		public static ConfigEntry<float> OffsetX_Left;

		public static ConfigEntry<float> OffsetY_Left;

		public static ConfigEntry<float> FontSize;

		public static ConfigEntry<string> HostSymbol;

		public static ConfigEntry<float> ConnectTimeout;

		public static ConfigEntry<float> RetryInterval;

		public static ConfigEntry<bool> EnableManualReconnect;

		public static ConfigEntry<bool> EnableGhostFix;

		public static ConfigEntry<int> MaxTotalLength;

		public static ConfigEntry<float> LatencyOffset;

		public static ConfigEntry<bool> AutoHideNormal;

		public static ConfigEntry<bool> ShowPingInNormal;

		public static ConfigEntry<bool> HideOnMenu;

		public static ConfigEntry<bool> EnableDebugLogs;

		public static ConfigEntry<bool> EnableVirtualTestPlayer;

		public static ConfigEntry<string> TestPlayerName;

		public const string MOD_VERSION = "v0.3.4 (EN)";

		private void Awake()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Expected O, but got Unknown
			Instance = this;
			logger = ((BaseUnityPlugin)this).Logger;
			debugLogger = new ManualLogSource("VoiceFixDebug");
			Logger.Sources.Add((ILogSource)(object)debugLogger);
			string text = "UI Settings";
			UIPositionSide = ((BaseUnityPlugin)this).Config.Bind<string>(text, "UI Position", "Right", new ConfigDescription("Choose which side of the screen the UI appears.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "Left", "Right" }), Array.Empty<object>()));
			ToggleUIKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>(text, "Toggle UI Key", (KeyCode)106, "Key to toggle the voice UI.");
			ShowProfessionalInfo = ((BaseUnityPlugin)this).Config.Bind<bool>(text, "Show Detailed Info", true, "Show IP addresses and debug info.");
			OffsetX_Right = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Right Margin", 20f, "Horizontal distance from the right edge.");
			OffsetY_Right = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Top Margin (Right)", 20f, "Vertical distance from the top edge.");
			OffsetX_Left = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Left Margin", 20f, "Horizontal distance from the left edge.");
			OffsetY_Left = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Top Margin (Left)", 20f, "Vertical distance from the top edge.");
			FontSize = ((BaseUnityPlugin)this).Config.Bind<float>(text, "Font Size", 21f, "Base font size for the UI.");
			HostSymbol = ((BaseUnityPlugin)this).Config.Bind<string>(text, "Host Symbol", "★", "Symbol displayed before the host's name.");
			string text2 = "Network Settings";
			ConnectTimeout = ((BaseUnityPlugin)this).Config.Bind<float>(text2, "Reconnect Timeout (s)", 25f, "Time in seconds before considering a connection dead.");
			RetryInterval = ((BaseUnityPlugin)this).Config.Bind<float>(text2, "Retry Interval (s)", 8f, "Cooldown between auto-reconnect attempts.");
			EnableManualReconnect = ((BaseUnityPlugin)this).Config.Bind<bool>(text2, "Enable Manual Reset (Alt+K)", true, "Allow Alt+K to force disconnect/reconnect.");
			EnableGhostFix = ((BaseUnityPlugin)this).Config.Bind<bool>(text2, "Enable ID Drift Fix", true, "Attempt to fix 'Unknown' names using scene data.");
			string text3 = "Advanced & Debug";
			MaxTotalLength = ((BaseUnityPlugin)this).Config.Bind<int>(text3, "Max Name Length", 26, new ConfigDescription("Max characters to display for names.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 60), Array.Empty<object>()));
			LatencyOffset = ((BaseUnityPlugin)this).Config.Bind<float>(text3, "Ping Offset", 350f, "Horizontal pixel offset for the Ping display.");
			AutoHideNormal = ((BaseUnityPlugin)this).Config.Bind<bool>(text3, "Auto Hide Simple UI", true, "Hide UI when everyone is connected normally.");
			ShowPingInNormal = ((BaseUnityPlugin)this).Config.Bind<bool>(text3, "Show Ping in Simple UI", true, "Show local ping in simple mode.");
			HideOnMenu = ((BaseUnityPlugin)this).Config.Bind<bool>(text3, "Hide on Menu", true, "Hide UI when the ESC menu is open.");
			EnableDebugLogs = ((BaseUnityPlugin)this).Config.Bind<bool>(text3, "Enable Debug Logs", false, "Output detailed network logs to console.");
			EnableVirtualTestPlayer = ((BaseUnityPlugin)this).Config.Bind<bool>(text3, "Enable Virtual Player", false, "Add a fake player for UI testing.");
			TestPlayerName = ((BaseUnityPlugin)this).Config.Bind<string>(text3, "Virtual Player Name", "1234567891012141618202224262830323436", "Name of the fake player.");
			Harmony.CreateAndPatchAll(typeof(LoadBalancingClientPatch), (string)null);
			Harmony.CreateAndPatchAll(typeof(PhotonRPCFix), (string)null);
			VoiceUIManager.CreateGlobalInstance();
			logger.LogInfo((object)"Better Voice Fix (v0.3.4 (EN)) Loaded.");
		}

		private void Update()
		{
			NetworkManager.SystemUpdate();
		}
	}
	public class VoiceUIManager : MonoBehaviour
	{
		private struct LogEntry
		{
			public string Time;

			public string Player;

			public string Msg;

			public bool IsLocal;
		}

		private class PlayerRenderData
		{
			public string Name;

			public string IP;

			public int Ping;

			public bool IsLocal;

			public bool IsHost;

			public bool IsAlive;

			public bool HasModData;

			public bool IsInVoiceRoom;

			public int ActorNumber;

			public byte RemoteState;
		}

		public static VoiceUIManager Instance;

		public TextMeshProUGUI statsText;

		private Canvas myCanvas;

		private bool showDebugConsole = false;

		private Rect debugWindowRect = new Rect(20f, 20f, 600f, 400f);

		private Vector2 debugScrollPosition;

		private Vector2 filterScrollPosition;

		private List<LogEntry> debugLogs = new List<LogEntry>();

		private int logFilterMode = 0;

		private int targetActorNumber = -1;

		private bool isResizing = false;

		private Rect resizeHandleRect;

		private Dictionary<int, float> joinTimes = new Dictionary<int, float>();

		private const string C_GREEN = "#90EE90";

		private const string C_PALE_GREEN = "#98FB98";

		private const string C_YELLOW = "#F0E68C";

		private const string C_RED = "#FF6961";

		private const string C_LOW_SAT_RED = "#CD5C5C";

		private const string C_TEXT = "#dfdac2";

		private const string C_GREY = "#808080";

		private const string C_GOLD = "#ffd700";

		private const string C_GHOST_GREEN = "#b2d3b2";

		private float nextUiUpdateTime = 0f;

		private bool isDetailMode = false;

		private float detailModeExpiry = 0f;

		private float lastFontRetryTime;

		private string notificationMsg = "";

		private float notificationExpiry = 0f;

		private bool wasSinglePlayer = false;

		private float singlePlayerEnterTime = 0f;

		public static void CreateGlobalInstance()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)Instance != (Object)null))
			{
				GameObject val = new GameObject("BetterVoiceFix_UI");
				Object.DontDestroyOnLoad((Object)(object)val);
				Canvas val2 = val.AddComponent<Canvas>();
				val2.renderMode = (RenderMode)0;
				val2.sortingOrder = 9999;
				CanvasScaler val3 = val.AddComponent<CanvasScaler>();
				val3.uiScaleMode = (ScaleMode)1;
				val3.referenceResolution = new Vector2(1920f, 1080f);
				Instance = val.AddComponent<VoiceUIManager>();
				Instance.myCanvas = val2;
				Instance.InitText();
			}
		}

		private void InitText()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			GameObject val = new GameObject("StatusText");
			val.transform.SetParent(((Component)this).transform, false);
			ContentSizeFitter val2 = val.AddComponent<ContentSizeFitter>();
			val2.horizontalFit = (FitMode)2;
			val2.verticalFit = (FitMode)2;
			statsText = val.AddComponent<TextMeshProUGUI>();
			((TMP_Text)statsText).richText = true;
			((Graphic)statsText).raycastTarget = false;
			((TMP_Text)statsText).overflowMode = (TextOverflowModes)0;
			((TMP_Text)statsText).textWrappingMode = (TextWrappingModes)0;
			UpdateLayout();
			TrySyncFontFromGame();
		}

		public void AddLog(string player, string msg, bool isLocal)
		{
			if (debugLogs.Count > 300)
			{
				debugLogs.RemoveAt(0);
			}
			debugLogs.Add(new LogEntry
			{
				Time = DateTime.Now.ToString("HH:mm:ss"),
				Player = player,
				Msg = msg,
				IsLocal = isLocal
			});
			debugScrollPosition.y = float.MaxValue;
		}

		private void OnGUI()
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			if (showDebugConsole)
			{
				GUI.skin.window.normal.background = Texture2D.blackTexture;
				GUI.backgroundColor = new Color(0f, 0f, 0f, 0.85f);
				debugWindowRect = GUI.Window(999, debugWindowRect, new WindowFunction(DrawDebugWindow), "Voice Fix Console (Alt+J) | EvCode:186");
			}
		}

		private void DrawDebugWindow(int windowID)
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0373: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03db: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0401: Invalid comparison between Unknown and I4
			//IL_0416: Unknown result type (might be due to invalid IL or missing references)
			//IL_041c: Invalid comparison between Unknown and I4
			//IL_0323: Unknown result type (might be due to invalid IL or missing references)
			//IL_0328: Unknown result type (might be due to invalid IL or missing references)
			//IL_033a: Expected O, but got Unknown
			//IL_043e: Unknown result type (might be due to invalid IL or missing references)
			//IL_045c: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Copy All", Array.Empty<GUILayoutOption>()))
			{
				ExportLogs(toFile: false);
			}
			if (GUILayout.Button("Export File", Array.Empty<GUILayoutOption>()))
			{
				ExportLogs(toFile: true);
			}
			if (GUILayout.Button("Clear", Array.Empty<GUILayoutOption>()))
			{
				debugLogs.Clear();
			}
			if (GUILayout.Button("Dump Voice Players", Array.Empty<GUILayoutOption>()))
			{
				DumpVoicePlayers();
			}
			GUILayout.EndHorizontal();
			filterScrollPosition = GUILayout.BeginScrollView(filterScrollPosition, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(40f) });
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button((logFilterMode == 0) ? "[★All]" : "All", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }))
			{
				logFilterMode = 0;
			}
			if (GUILayout.Button((logFilterMode == 1) ? "[★Local]" : "Local", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }))
			{
				logFilterMode = 1;
			}
			if (PhotonNetwork.InRoom)
			{
				Player[] playerList = PhotonNetwork.PlayerList;
				foreach (Player val in playerList)
				{
					if (!val.IsLocal)
					{
						string playerName = NetworkManager.GetPlayerName(val.ActorNumber);
						string text = ((playerName.Length > 9) ? playerName.Substring(0, 9) : playerName);
						string text2 = ((logFilterMode == -1 && targetActorNumber == val.ActorNumber) ? ("[★" + text + "]") : text);
						if (GUILayout.Button(text2, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(80f) }))
						{
							logFilterMode = -1;
							targetActorNumber = val.ActorNumber;
						}
					}
				}
			}
			GUILayout.EndHorizontal();
			GUILayout.EndScrollView();
			debugScrollPosition = GUILayout.BeginScrollView(debugScrollPosition, Array.Empty<GUILayoutOption>());
			foreach (LogEntry debugLog in debugLogs)
			{
				if (logFilterMode == 1 && !debugLog.IsLocal)
				{
					continue;
				}
				if (logFilterMode == -1)
				{
					string playerName2 = NetworkManager.GetPlayerName(targetActorNumber);
					if (debugLog.Player != playerName2)
					{
						continue;
					}
				}
				string text3 = (debugLog.IsLocal ? "cyan" : "yellow");
				if (debugLog.Player == "System")
				{
					text3 = "white";
				}
				GUILayout.Label("<color=" + text3 + ">[" + debugLog.Time + "] " + debugLog.Player + ":</color> " + debugLog.Msg, new GUIStyle(GUI.skin.label)
				{
					richText = true
				}, Array.Empty<GUILayoutOption>());
			}
			GUILayout.EndScrollView();
			GUI.DragWindow(new Rect(0f, 0f, 10000f, 20f));
			resizeHandleRect = new Rect(((Rect)(ref debugWindowRect)).width - 20f, ((Rect)(ref debugWindowRect)).height - 20f, 20f, 20f);
			GUI.Label(resizeHandleRect, "◢");
			Event current2 = Event.current;
			if ((int)current2.type == 0 && ((Rect)(ref resizeHandleRect)).Contains(current2.mousePosition))
			{
				isResizing = true;
			}
			else if ((int)current2.type == 1)
			{
				isResizing = false;
			}
			else if ((int)current2.type == 3 && isResizing)
			{
				ref Rect reference = ref debugWindowRect;
				((Rect)(ref reference)).width = ((Rect)(ref reference)).width + current2.delta.x;
				ref Rect reference2 = ref debugWindowRect;
				((Rect)(ref reference2)).height = ((Rect)(ref reference2)).height + current2.delta.y;
				if (((Rect)(ref debugWindowRect)).width < 300f)
				{
					((Rect)(ref debugWindowRect)).width = 300f;
				}
				if (((Rect)(ref debugWindowRect)).height < 200f)
				{
					((Rect)(ref debugWindowRect)).height = 200f;
				}
			}
		}

		private void DumpVoicePlayers()
		{
			if ((Object)(object)NetworkManager.punVoice == (Object)null || ((VoiceConnection)NetworkManager.punVoice).Client == null || ((LoadBalancingClient)((VoiceConnection)NetworkManager.punVoice).Client).CurrentRoom == null)
			{
				AddLog("System", "Client Not Connected", isLocal: true);
				return;
			}
			StringBuilder stringBuilder = new StringBuilder();
			Dictionary<int, Player> players = ((LoadBalancingClient)((VoiceConnection)NetworkManager.punVoice).Client).CurrentRoom.Players;
			stringBuilder.AppendLine($"=== Voice Player Dump (Count: {players.Count}) ===");
			foreach (KeyValuePair<int, Player> item in players)
			{
				int key = item.Key;
				string playerName = NetworkManager.GetPlayerName(key);
				bool flag = NetworkManager.IsGhost(key);
				string text = "N/A";
				string text2 = "";
				if (NetworkManager.PlayerCache.ContainsKey(key))
				{
					text = NetworkManager.PlayerCache[key].IP;
					text2 = NetworkManager.PlayerCache[key].ModVersion;
				}
				string text3 = (flag ? " [Ghost]" : "");
				string text4 = (string.IsNullOrEmpty(text2) ? "" : (" | Ver: " + text2));
				stringBuilder.AppendLine($" - ID: {key} | Name: {playerName} | IP: {text}{text4}{text3}");
			}
			AddLog("System", stringBuilder.ToString(), isLocal: true);
		}

		private void ExportLogs(bool toFile)
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine($"=== Log Export ({DateTime.Now}) ===");
			foreach (LogEntry debugLog in debugLogs)
			{
				stringBuilder.AppendLine("[" + debugLog.Time + "] " + debugLog.Player + ": " + debugLog.Msg);
			}
			if (toFile)
			{
				string text = Path.Combine(Paths.BepInExRootPath, "Log", "BetterVoiceFix_Dump.txt");
				try
				{
					File.WriteAllText(text, stringBuilder.ToString());
					AddLog("System", "Exported: " + text, isLocal: true);
					return;
				}
				catch (Exception ex)
				{
					AddLog("System", "Failed: " + ex.Message, isLocal: true);
					return;
				}
			}
			GUIUtility.systemCopyBuffer = stringBuilder.ToString();
			AddLog("System", "Copied to Clipboard", isLocal: true);
		}

		private void Update()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			if (VoiceFix.ToggleUIKey == null)
			{
				return;
			}
			if (Input.GetKeyDown(VoiceFix.ToggleUIKey.Value))
			{
				if (isDetailMode)
				{
					isDetailMode = false;
					detailModeExpiry = 0f;
				}
				else
				{
					isDetailMode = true;
					detailModeExpiry = Time.unscaledTime + 10f;
				}
			}
			if ((Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307)) && Input.GetKeyDown((KeyCode)106))
			{
				showDebugConsole = !showDebugConsole;
			}
			if (isDetailMode && Time.unscaledTime > detailModeExpiry)
			{
				isDetailMode = false;
			}
			Scene activeScene = SceneManager.GetActiveScene();
			string name = ((Scene)(ref activeScene)).name;
			bool flag = name == "Airport";
			bool inRoom = PhotonNetwork.InRoom;
			bool flag2 = VoiceFix.HideOnMenu != null && VoiceFix.HideOnMenu.Value && Cursor.visible;
			bool flag3 = false;
			if (inRoom && !flag2)
			{
				if (isDetailMode)
				{
					flag3 = true;
				}
				else
				{
					bool flag4 = Time.unscaledTime < notificationExpiry;
					if (flag || flag4)
					{
						flag3 = true;
					}
				}
			}
			if (((Behaviour)myCanvas).enabled != flag3)
			{
				((Behaviour)myCanvas).enabled = flag3;
			}
			if (!flag3)
			{
				return;
			}
			if ((Object)(object)((TMP_Text)statsText).font == (Object)null || ((Object)((TMP_Text)statsText).font).name.Contains("Liberation") || Time.unscaledTime - lastFontRetryTime > 2f)
			{
				lastFontRetryTime = Time.unscaledTime;
				TrySyncFontFromGame();
			}
			if (Time.unscaledTime > nextUiUpdateTime)
			{
				if (isDetailMode)
				{
					UpdateContent_Detail();
				}
				else
				{
					UpdateContent_Normal();
				}
				UpdateLayout();
				nextUiUpdateTime = Time.unscaledTime + 0.2f;
			}
		}

		public bool IsDetailModeActive()
		{
			return isDetailMode;
		}

		private void UpdateLayout()
		{
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)statsText == (Object)null) && VoiceFix.UIPositionSide != null)
			{
				bool flag = VoiceFix.UIPositionSide.Value == "Right";
				float num = (flag ? Mathf.Abs(VoiceFix.OffsetX_Right.Value) : Mathf.Abs(VoiceFix.OffsetX_Left.Value));
				float num2 = (flag ? Mathf.Abs(VoiceFix.OffsetY_Right.Value) : Mathf.Abs(VoiceFix.OffsetY_Left.Value));
				RectTransform rectTransform = ((TMP_Text)statsText).rectTransform;
				if (flag)
				{
					rectTransform.anchorMin = new Vector2(1f, 1f);
					rectTransform.anchorMax = new Vector2(1f, 1f);
					rectTransform.pivot = new Vector2(1f, 1f);
					rectTransform.anchoredPosition = new Vector2(0f - num, 0f - num2);
					((TMP_Text)statsText).alignment = (TextAlignmentOptions)257;
				}
				else
				{
					rectTransform.anchorMin = new Vector2(0f, 1f);
					rectTransform.anchorMax = new Vector2(0f, 1f);
					rectTransform.pivot = new Vector2(0f, 1f);
					rectTransform.anchoredPosition = new Vector2(num, 0f - num2);
					((TMP_Text)statsText).alignment = (TextAlignmentOptions)257;
				}
				((TMP_Text)statsText).fontSize = VoiceFix.FontSize.Value;
			}
		}

		public void TriggerNotification(string playerName)
		{
			notificationMsg = "<color=#dfdac2>" + playerName + ":</color> " + FormatStatusTag("Disconnected", "#F0E68C");
			notificationExpiry = Time.unscaledTime + 5f;
		}

		public void ShowStatsTemporary()
		{
			notificationMsg = "<color=#F0E68C>[System] Manual Action...</color>";
			notificationExpiry = Time.unscaledTime + 5f;
		}

		private string GetLocalizedState(ClientState state)
		{
			//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_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Invalid comparison between Unknown and I4
			ClientState val = state;
			ClientState val2 = val;
			if ((int)val2 != 9)
			{
				if ((int)val2 == 14)
				{
					return "Disconnected";
				}
				return ((object)(ClientState)(ref state)).ToString();
			}
			return "Connected";
		}

		private string GetMyStateRaw(out string color)
		{
			int joined = 0;
			int total = 0;
			GetVoiceCounts(out joined, out total);
			if (IsVoiceConnected())
			{
				if (joined > 1)
				{
					color = "#90EE90";
					return "Synced";
				}
				if (joined == 1 && PhotonNetwork.CurrentRoom.PlayerCount > 1)
				{
					color = "#F0E68C";
					return "Isolated";
				}
				color = "#90EE90";
				return "Synced";
			}
			if (IsConnectingLocal())
			{
				color = "#F0E68C";
				return "Connecting";
			}
			color = "#FF6961";
			return "Disconnected";
		}

		private void AppendCommonStats(StringBuilder sb, bool forceShow)
		{
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			bool flag = PhotonNetwork.OfflineMode || (PhotonNetwork.CurrentRoom != null && PhotonNetwork.CurrentRoom.MaxPlayers == 1);
			if (flag)
			{
				if (!wasSinglePlayer)
				{
					singlePlayerEnterTime = Time.unscaledTime;
					wasSinglePlayer = true;
				}
			}
			else
			{
				wasSinglePlayer = false;
			}
			if (!(!forceShow && flag) || !(Time.unscaledTime > singlePlayerEnterTime + 10f))
			{
				if (flag)
				{
					sb.Append("<color=#dfdac2>Local Voice: Singleplayer</color>\n");
				}
				else
				{
					string color;
					string myStateRaw = GetMyStateRaw(out color);
					string text = myStateRaw;
					if ((Object)(object)NetworkManager.punVoice != (Object)null && ((VoiceConnection)NetworkManager.punVoice).Client != null && myStateRaw != "Synced" && myStateRaw != "Isolated")
					{
						text = GetLocalizedState(((LoadBalancingClient)((VoiceConnection)NetworkManager.punVoice).Client).State);
					}
					sb.Append("<color=#dfdac2>Local Voice: </color>");
					if (IsVoiceConnected())
					{
						if (PhotonNetwork.IsMasterClient)
						{
							sb.Append("<color=#dfdac2>Connected</color>");
						}
						else
						{
							sb.Append("<color=#dfdac2>Connected</color> " + FormatStatusTag(myStateRaw, color));
						}
					}
					else
					{
						sb.Append("<color=" + color + ">" + text + "</color>");
					}
					sb.Append("\n");
					GetVoiceCounts(out var _, out var total);
					int ghostCount = NetworkManager.GetGhostCount();
					int count = ((LoadBalancingClient)((VoiceConnection)NetworkManager.punVoice).Client).CurrentRoom.Players.Count;
					int num = total;
					sb.Append("<color=#dfdac2>Voice Count: </color>");
					string arg = "#F0E68C";
					if (count == 1 && num >= 3)
					{
						arg = "#FF6961";
					}
					else if (ghostCount > 0)
					{
						arg = "#b2d3b2";
					}
					else if (count == num)
					{
						arg = "#90EE90";
					}
					sb.Append($"<color={arg}>{count}</color>");
					sb.Append(string.Format("<color={0}>/</color><color={1}>{2}</color>", "#dfdac2", "#dfdac2", num));
					if (ghostCount > 0)
					{
						sb.Append(string.Format(" <color={0}>(</color><color={1}>{2}</color><color={3}> Ghosts)</color>", "#dfdac2", "#b2d3b2", ghostCount, "#dfdac2"));
					}
					sb.Append("\n");
				}
				if (VoiceFix.ShowPingInNormal != null && VoiceFix.ShowPingInNormal.Value)
				{
					int ping = PhotonNetwork.GetPing();
					string arg2 = ((ping < 100) ? "#90EE90" : ((ping < 200) ? "#F0E68C" : "#FF6961"));
					sb.Append(string.Format("<color={0}>Ping: </color><color={1}>{2}ms</color>\n", "#dfdac2", arg2, ping));
				}
			}
			if (Time.unscaledTime < notificationExpiry)
			{
				sb.Append(notificationMsg + "\n");
			}
		}

		private void UpdateContent_Normal()
		{
			StringBuilder stringBuilder = new StringBuilder();
			AppendCommonStats(stringBuilder, forceShow: false);
			((TMP_Text)statsText).text = stringBuilder.ToString();
		}

		private void UpdateContent_Detail()
		{
			StringBuilder stringBuilder = new StringBuilder();
			bool value = VoiceFix.ShowProfessionalInfo.Value;
			float value2 = VoiceFix.LatencyOffset.Value;
			stringBuilder.Append("<align=\"center\"><size=120%><color=#dfdac2>Voice Status (v0.3.4 (EN))</color></size></align>\n");
			stringBuilder.Append("<align=\"center\"><color=#dfdac2>------------------</color></align>\n");
			string currentIP = GetCurrentIP();
			string color;
			string myStateRaw = GetMyStateRaw(out color);
			stringBuilder.Append("<size=75%><color=#dfdac2>My IP:</color> ");
			if (!PhotonNetwork.IsMasterClient || !IsVoiceConnected())
			{
				string text = FormatStatusTag(myStateRaw, color);
				stringBuilder.Append(text + " ");
			}
			if (value)
			{
				stringBuilder.Append(" <color=#dfdac2>" + currentIP + "</color>");
			}
			stringBuilder.Append("\n");
			stringBuilder.Append("<color=#dfdac2>Host IP:</color> ");
			if (PhotonNetwork.IsMasterClient)
			{
				GetVoiceCounts(out var joined, out var total);
				int num = total - joined;
				if (num < 0)
				{
					num = 0;
				}
				stringBuilder.Append("<color=#dfdac2>[</color><color=#dfdac2>Self</color><color=#dfdac2>]</color> ");
				string text2 = ((joined >= total) ? "#90EE90" : "#F0E68C");
				stringBuilder.Append(string.Format("<color={0}>[</color><color={1}>Sync:</color><color={2}>{3}/{4}</color><color={5}>]</color> ", "#dfdac2", "#dfdac2", text2, joined, total, "#dfdac2"));
				string text3 = ((num > 0) ? "#CD5C5C" : "#dfdac2");
				stringBuilder.Append(string.Format("<color={0}>[</color><color={1}>Diff:</color><color={2}>{3}</color><color={4}>]</color>", "#dfdac2", "#dfdac2", text3, num, "#dfdac2"));
			}
			else
			{
				Player masterClient = PhotonNetwork.MasterClient;
				string s = ((masterClient != null) ? NetworkManager.GetPlayerName(masterClient.ActorNumber) : "Unknown");
				string text4 = "";
				if (masterClient != null && NetworkManager.PlayerCache.TryGetValue(masterClient.ActorNumber, out var value3))
				{
					text4 = value3.IP;
				}
				stringBuilder.Append("<color=#dfdac2>[" + Truncate(s, 0, isHost: false) + "]</color>");
				if (!string.IsNullOrEmpty(text4))
				{
					stringBuilder.Append("<color=#dfdac2>: " + text4 + "</color>");
				}
			}
			stringBuilder.Append("</size>\n");
			if (PhotonNetwork.IsMasterClient)
			{
				int c;
				string majorityIP = GetMajorityIP(out c);
				if (c > 2 && !string.IsNullOrEmpty(majorityIP) && majorityIP != currentIP)
				{
					stringBuilder.Append(string.Format("<color={0}><size=85%>⚠ [WARN] Majority({1}) on diff channel!</size></color>\n", "#F0E68C", c));
				}
			}
			int ghostCount = NetworkManager.GetGhostCount();
			List<PlayerRenderData> list = new List<PlayerRenderData>();
			if (VoiceFix.EnableVirtualTestPlayer != null && VoiceFix.EnableVirtualTestPlayer.Value)
			{
				string name = ((VoiceFix.TestPlayerName != null) ? VoiceFix.TestPlayerName.Value : "Test");
				list.Add(new PlayerRenderData
				{
					Name = "VirtualPlayer1",
					IP = "",
					Ping = 0,
					IsLocal = false,
					IsHost = false,
					IsAlive = true,
					HasModData = false,
					IsInVoiceRoom = false
				});
				list.Add(new PlayerRenderData
				{
					Name = name,
					IP = currentIP,
					Ping = 50,
					IsLocal = false,
					IsHost = false,
					IsAlive = true,
					HasModData = true,
					IsInVoiceRoom = true
				});
			}
			HashSet<int> hashSet = new HashSet<int>();
			if (PhotonNetwork.PlayerList != null)
			{
				Player[] playerList = PhotonNetwork.PlayerList;
				foreach (Player val in playerList)
				{
					int actorNumber = val.ActorNumber;
					hashSet.Add(actorNumber);
					string text5 = "";
					int ping = 0;
					bool hasModData = false;
					bool isLocal = val.IsLocal;
					bool isMasterClient = val.IsMasterClient;
					bool isInVoiceRoom = false;
					if ((Object)(object)NetworkManager.punVoice != (Object)null && ((VoiceConnection)NetworkManager.punVoice).Client != null && ((LoadBalancingClient)((VoiceConnection)NetworkManager.punVoice).Client).CurrentRoom != null)
					{
						isInVoiceRoom = ((LoadBalancingClient)((VoiceConnection)NetworkManager.punVoice).Client).CurrentRoom.Players.ContainsKey(actorNumber);
					}
					if (isLocal)
					{
						text5 = GetCurrentIP();
						ping = PhotonNetwork.GetPing();
						hasModData = true;
						isInVoiceRoom = IsVoiceConnected();
					}
					else
					{
						if (((Dictionary<object, object>)(object)val.CustomProperties).TryGetValue((object)"PVF_IP", out object value4))
						{
							text5 = (string)value4;
						}
						if (((Dictionary<object, object>)(object)val.CustomProperties).TryGetValue((object)"PVF_Ping", out object value5))
						{
							ping = (int)value5;
						}
						if (!string.IsNullOrEmpty(text5))
						{
							hasModData = true;
						}
					}
					string playerName = NetworkManager.GetPlayerName(actorNumber);
					byte remoteState = 0;
					if (NetworkManager.PlayerCache.ContainsKey(actorNumber))
					{
						remoteState = NetworkManager.PlayerCache[actorNumber].RemoteState;
					}
					list.Add(new PlayerRenderData
					{
						Name = playerName,
						IP = text5,
						Ping = ping,
						IsLocal = isLocal,
						IsHost = isMasterClient,
						IsAlive = true,
						HasModData = hasModData,
						IsInVoiceRoom = isInVoiceRoom,
						ActorNumber = actorNumber,
						RemoteState = remoteState
					});
				}
			}
			foreach (KeyValuePair<int, CacheEntry> item in NetworkManager.PlayerCache)
			{
				int key = item.Key;
				if (!hashSet.Contains(key) && !(Time.unscaledTime - item.Value.LastSeenTime > 5f))
				{
					list.Add(new PlayerRenderData
					{
						Name = item.Value.PlayerName,
						IP = item.Value.IP,
						Ping = 0,
						IsLocal = false,
						IsHost = false,
						IsAlive = false,
						HasModData = true,
						IsInVoiceRoom = false,
						ActorNumber = key,
						RemoteState = item.Value.RemoteState
					});
				}
			}
			list.Sort((PlayerRenderData a, PlayerRenderData b) => b.IsLocal.CompareTo(a.IsLocal));
			stringBuilder.Append("<line-height=105%>");
			foreach (PlayerRenderData item2 in list)
			{
				BuildPlayerEntry(stringBuilder, item2.Name, item2.IP, item2.Ping, item2.IsLocal, item2.IsHost, value, value2, item2.IsAlive, item2.HasModData, item2.IsInVoiceRoom, ghostCount > 0, item2.ActorNumber, item2.RemoteState);
			}
			stringBuilder.Append("</line-height>");
			stringBuilder.Append("<align=\"center\"><color=#dfdac2>------------------</color></align>\n");
			AppendCommonStats(stringBuilder, forceShow: true);
			if (NetworkManager.ActiveSOSList.Count > 0)
			{
				stringBuilder.Append("<align=\"center\"><color=#dfdac2>------------------</color></align>\n");
				stringBuilder.Append("<color=#F0E68C>[SOS Snapshot]</color>\n");
				int c2;
				string majorityIP2 = GetMajorityIP(out c2);
				string text6 = ((PhotonNetwork.IsMasterClient || IsIPMatch(majorityIP2)) ? "Synced" : majorityIP2);
				stringBuilder.Append(string.Format("<size=80%><color={0}>Majority: {1} ({2})</color></size>\n", "#dfdac2", majorityIP2, c2));
				foreach (SOSData activeSOS in NetworkManager.ActiveSOSList)
				{
					stringBuilder.Append("<size=80%><color=#FF6961>DETECTED " + activeSOS.PlayerName + " DROP</color></size>\n");
					string text7 = (string.IsNullOrEmpty(activeSOS.OriginIP) ? "Unknown" : activeSOS.OriginIP);
					stringBuilder.Append("  <size=80%><color=#dfdac2>Tgt: (" + activeSOS.TargetIP + ") | Last: " + text7 + "</color></size>\n");
				}
			}
			if (value)
			{
				stringBuilder.Append("<align=\"center\"><color=#dfdac2>------------------</color></align>\n");
				int c3;
				string majorityIP3 = GetMajorityIP(out c3);
				float num2 = Time.unscaledTime - NetworkManager.LastScanTime;
				stringBuilder.Append(string.Format("<size=80%><color={0}>[Cache] ({1:F0}s ago)</color>\n", "#dfdac2", num2));
				stringBuilder.Append(string.Format("<color={0}>Majority:</color> <color={1}>{2}</color> <color={3}>({4})</color>\n", "#dfdac2", "#dfdac2", majorityIP3, "#dfdac2", c3));
				IEnumerable<IGrouping<string, KeyValuePair<int, CacheEntry>>> enumerable = from x in NetworkManager.PlayerCache
					group x by x.Value.IP;
				foreach (IGrouping<string, KeyValuePair<int, CacheEntry>> item3 in enumerable)
				{
					if (!(item3.Key == majorityIP3))
					{
						string text8 = (string.IsNullOrEmpty(item3.Key) ? "Unlinked" : item3.Key);
						IEnumerable<string> values = item3.Select((KeyValuePair<int, CacheEntry> x) => x.Value.PlayerName).Take(3);
						string text9 = string.Join(",", values);
						stringBuilder.Append("<color=#dfdac2> - " + text8 + ": " + text9 + "</color>\n");
					}
				}
				if (NetworkManager.HostHistory.Count > 0)
				{
					stringBuilder.Append("<color=#dfdac2>[History]</color> " + NetworkManager.HostHistory[NetworkManager.HostHistory.Count - 1] + "\n");
				}
				stringBuilder.Append("</size>");
			}
			((TMP_Text)statsText).text = stringBuilder.ToString();
		}

		private string GetClientStateLocalized(ClientState state)
		{
			return ((object)(ClientState)(ref state)).ToString();
		}

		private void BuildPlayerEntry(StringBuilder sb, string name, string ip, int ping, bool isLocal, bool isHost, bool pro, float alignX, bool isAlive, bool hasModData, bool isInVoiceRoom, bool hasGhosts, int actorNumber = -1, byte remoteState = 0)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Invalid comparison between Unknown and I4
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Invalid comparison between Unknown and I4
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Invalid comparison between Unknown and I4
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0546: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			if (!hasModData)
			{
				string text = (isHost ? ("<color=#ffd700>" + VoiceFix.HostSymbol.Value + " </color>") : "");
				string text2 = "Unknown";
				string colorHex = "#dfdac2";
				bool flag = false;
				string text3 = "";
				if (isInVoiceRoom)
				{
					text2 = "Synced";
					colorHex = "#98FB98";
				}
				else if (remoteState != 0)
				{
					ClientState val = (ClientState)remoteState;
					if ((int)val == 14 || (int)val == 13)
					{
						text2 = "Broken";
						colorHex = "#FF6961";
					}
					else if ((int)val == 9)
					{
						text2 = "Synced";
						colorHex = "#98FB98";
					}
					else
					{
						text2 = "Joining";
						colorHex = "#F0E68C";
						flag = true;
						text3 = GetClientStateLocalized(val);
						if (actorNumber != -1)
						{
							joinTimes[actorNumber] = Time.unscaledTime;
						}
					}
				}
				else if (actorNumber != -1)
				{
					if (!joinTimes.ContainsKey(actorNumber))
					{
						joinTimes[actorNumber] = Time.unscaledTime;
					}
					if (Time.unscaledTime - joinTimes[actorNumber] < 25f)
					{
						text2 = "Joining";
						colorHex = "#F0E68C";
					}
					else if (hasGhosts)
					{
						text2 = "Drift";
						colorHex = "#b2d3b2";
					}
					else
					{
						text2 = "Broken";
						colorHex = "#FF6961";
					}
				}
				num = 8;
				string text4 = Truncate(name, num, isHost);
				sb.Append(FormatStatusTag(text2, colorHex) + " " + text + "<size=100%><color=#90EE90>" + text4 + "</color></size>\n");
				if (flag && pro)
				{
					sb.Append("<voffset=0.17em><size=80%><color=#dfdac2>  » " + text3 + "</color></size></voffset>\n");
				}
				return;
			}
			bool flag2 = !string.IsNullOrEmpty(ip);
			string text5 = "";
			string text6 = "#90EE90";
			bool flag3 = false;
			if (!flag2)
			{
				if (isAlive && ping > 0)
				{
					text5 = "Link...";
					text6 = "#F0E68C";
					flag3 = true;
					num = 8;
				}
				else
				{
					text5 = "Broken";
					text6 = "#FF6961";
					num = 6;
				}
			}
			else if (IsIPMatch(ip))
			{
				text5 = "Synced";
				text6 = "#90EE90";
				num = 6;
			}
			else
			{
				text5 = "Diff";
				text6 = "#CD5C5C";
				num = 6;
			}
			if (isLocal)
			{
				num = 6;
				if (IsConnectingLocal())
				{
					flag3 = true;
				}
			}
			if (!isAlive && !isLocal)
			{
				text5 = "Gone";
				text6 = "#808080";
				num = 6;
			}
			string text7 = FormatStatusTag(text5, text6);
			string text8 = (isHost ? ("<color=#ffd700>" + VoiceFix.HostSymbol.Value + " </color>") : "");
			if (isLocal)
			{
				text7 = "<color=#dfdac2>[</color><color=#dfdac2>Self</color><color=#dfdac2>]</color>";
			}
			string text9 = Truncate(name, num, isHost);
			string text10 = ((!isAlive && !isLocal) ? "#808080" : "#90EE90");
			string text11 = "";
			string text12 = ((ping < 100) ? "#90EE90" : ((ping < 200) ? "#F0E68C" : "#FF6961"));
			if (ping > 0 || (isAlive && string.IsNullOrEmpty(ip)))
			{
				text11 = string.Format("<pos={0}><color={1}>| Ping:</color><color={2}>{3}ms</color>", alignX, "#dfdac2", text12, ping);
			}
			sb.Append(text7 + " " + text8 + "<size=100%><color=" + text10 + ">" + text9 + "</color></size>" + text11 + "\n");
			if (pro && !isLocal)
			{
				string text13 = ip;
				string text14 = "Connected";
				if (remoteState != 0 && remoteState != 9 && remoteState != 14)
				{
					text13 = GetClientStateLocalized((ClientState)remoteState);
					text14 = "State";
					sb.Append("<voffset=0.17em><size=80%><color=#dfdac2>  » " + text13 + "</color></size></voffset>\n");
					return;
				}
				string text15 = (flag3 ? "(Wait Data...)" : (string.IsNullOrEmpty(ip) ? "N/A" : ip));
				if (flag3 && string.IsNullOrEmpty(ip))
				{
					text15 = "<color=grey>Fetch...</color>";
				}
				string text16 = (flag3 ? "Linking" : "Linked");
				sb.Append("<voffset=0.17em><size=80%><color=#dfdac2>  » " + text16 + ": " + text15 + "</color></size></voffset>\n");
			}
			else if (pro && isLocal && flag3)
			{
				string text17 = "Connecting...";
				if ((Object)(object)NetworkManager.punVoice != (Object)null && ((VoiceConnection)NetworkManager.punVoice).Client != null)
				{
					text17 = GetClientStateLocalized(((LoadBalancingClient)((VoiceConnection)NetworkManager.punVoice).Client).State);
				}
				sb.Append("<voffset=0.17em><size=80%><color=#dfdac2>  » " + text17 + "</color></size></voffset>\n");
			}
		}

		private void GetVoiceCounts(out int joined, out int total)
		{
			joined = 0;
			total = 0;
			if (PhotonNetwork.PlayerList == null)
			{
				return;
			}
			total = PhotonNetwork.PlayerList.Length;
			if ((Object)(object)NetworkManager.punVoice != (Object)null && ((VoiceConnection)NetworkManager.punVoice).Client != null && ((LoadBalancingClient)((VoiceConnection)NetworkManager.punVoice).Client).CurrentRoom != null)
			{
				foreach (int key in ((LoadBalancingClient)((VoiceConnection)NetworkManager.punVoice).Client).CurrentRoom.Players.Keys)
				{
					if (!NetworkManager.IsGhost(key))
					{
						joined++;
					}
				}
				return;
			}
			Player[] playerList = PhotonNetwork.PlayerList;
			foreach (Player val in playerList)
			{
				CacheEntry value;
				if (val.IsLocal)
				{
					if (IsVoiceConnected())
					{
						joined++;
					}
				}
				else if (NetworkManager.PlayerCache.TryGetValue(val.ActorNumber, out value) && !string.IsNullOrEmpty(value.IP))
				{
					joined++;
				}
			}
		}

		private string FormatStatusTag(string text, string colorHex)
		{
			return "<color=#dfdac2>[</color><color=" + colorHex + ">" + text + "</color><color=#dfdac2>]</color>";
		}

		private LoadBalancingClient GetVoiceClient()
		{
			if ((Object)(object)NetworkManager.punVoice != (Object)null)
			{
				return (LoadBalancingClient)(object)((VoiceConnection)NetworkManager.punVoice).Client;
			}
			GameObject val = GameObject.Find("VoiceClient");
			if ((Object)(object)val != (Object)null)
			{
				PunVoiceClient component = val.GetComponent<PunVoiceClient>();
				if ((Object)(object)component != (Object)null)
				{
					return (LoadBalancingClient)(object)((VoiceConnection)component).Client;
				}
			}
			return null;
		}

		private string GetCurrentIP()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			LoadBalancingClient voiceClient = GetVoiceClient();
			return (voiceClient != null && (int)voiceClient.State == 9) ? voiceClient.GameServerAddress : "";
		}

		private bool IsVoiceConnected()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			LoadBalancingClient voiceClient = GetVoiceClient();
			return voiceClient != null && (int)voiceClient.State == 9;
		}

		private bool IsConnectingLocal()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Invalid comparison between Unknown and I4
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			LoadBalancingClient voiceClient = GetVoiceClient();
			return voiceClient != null && ((int)voiceClient.State == 6 || (int)voiceClient.State == 1);
		}

		private bool IsMismatch()
		{
			if (NetworkManager.WrongIPCount > 2)
			{
				return true;
			}
			string targetGameServer = NetworkManager.TargetGameServer;
			string currentIP = GetCurrentIP();
			return !string.IsNullOrEmpty(targetGameServer) && !string.IsNullOrEmpty(currentIP) && targetGameServer != currentIP;
		}

		private bool IsIPMatch(string otherIP)
		{
			return otherIP == GetCurrentIP();
		}

		private string GetMajorityIP(out int c)
		{
			return NetworkManager.GetMajorityIP(out c);
		}

		private bool IsAllGood()
		{
			return IsVoiceConnected() && !IsMismatch() && NetworkManager.TotalRetryCount == 0;
		}

		private string Truncate(string s, int prefixWeight, bool isHost)
		{
			if (string.IsNullOrEmpty(s))
			{
				return "";
			}
			int num = 26;
			if (VoiceFix.MaxTotalLength != null)
			{
				num = VoiceFix.MaxTotalLength.Value;
			}
			int num2 = num - prefixWeight;
			if (num2 < 6)
			{
				num2 = 6;
			}
			if (isHost)
			{
				num2 -= 2;
			}
			int num3 = 0;
			for (int i = 0; i < s.Length; i++)
			{
				int num4 = ((s[i] <= 'ÿ') ? 1 : 2);
				if (num3 + num4 > num2)
				{
					return s.Substring(0, i) + "...";
				}
				num3 += num4;
			}
			return s;
		}

		private void TrySyncFontFromGame()
		{
			if (!((Object)(object)statsText == (Object)null))
			{
				PlayerConnectionLog val = Object.FindFirstObjectByType<PlayerConnectionLog>();
				if ((Object)(object)val != (Object)null && (Object)(object)val.text != (Object)null)
				{
					((TMP_Text)statsText).font = ((TMP_Text)val.text).font;
					((TMP_Text)statsText).fontSharedMaterial = ((TMP_Text)val.text).fontSharedMaterial;
				}
			}
		}
	}
}
namespace PeakVoiceFix.Patches
{
	[HarmonyPatch(typeof(LoadBalancingClient))]
	public class LoadBalancingClientPatch
	{
		[HarmonyPatch("OnEvent")]
		[HarmonyPrefix]
		public static void OnEventPrefix(EventData photonEvent)
		{
			if (photonEvent.Code == 186)
			{
				NetworkManager.OnEvent(photonEvent);
			}
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}