Decompiled source of QuacksPeakMod v1.1.0

BepInEx/plugins/BetterPeakVoiceFix.dll

Decompiled 6 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
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("BetterPeakVoiceFix")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.2.0")]
[assembly: AssemblyInformationalVersion("1.0.2+d55073ad32ec27c6a40cf9eee51ea95bd1307645")]
[assembly: AssemblyProduct("BetterPeakVoiceFix")]
[assembly: AssemblyTitle("BetterPeakVoiceFix")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.2.0")]
[module: UnverifiableCode]
namespace PeakVoiceFix
{
	public static class L
	{
		private static string _lang = "中文";

		private static Dictionary<string, string> _current;

		private static readonly Dictionary<string, string> ZH = new Dictionary<string, string>
		{
			{ "ui_title", "语音详细状态" },
			{ "ui_debug_title", "语音修复调试控制台 (Alt+J) | EvCode:186" },
			{ "btn_copy_all", "复制全部" },
			{ "btn_export", "导出文件" },
			{ "btn_clear", "清空" },
			{ "btn_dump", "打印语音底层名单" },
			{ "filter_all", "全部" },
			{ "filter_local", "本机" },
			{ "client_not_connected", "客户端未连接" },
			{ "voice_player_list", "语音底层名单" },
			{ "ghost_tag", "[幽灵]" },
			{ "exported_to", "已导出" },
			{ "export_failed", "失败" },
			{ "copied", "已复制" },
			{ "voice_single_player", "本机语音: 单人游戏" },
			{ "voice_local", "本机语音: " },
			{ "voice_connected", "已连接" },
			{ "voice_count", "语音连接人数:" },
			{ "id_mismatch", "人ID错位" },
			{ "local_ping", "本机延迟: " },
			{ "local_server", "本机已连服务器:" },
			{ "host_server", "房主已连服务器:" },
			{ "label_local", "本机" },
			{ "label_sync", "同步:" },
			{ "label_abnormal", "异常:" },
			{ "warn_majority", "⚠ [警告] 多数玩家({0}人)在另一频道!" },
			{ "virtual_player", "虚拟玩家1" },
			{ "sos_snapshot", "[SOS快照]" },
			{ "sos_majority", "多数派" },
			{ "sos_person", "人" },
			{ "sos_detected", "检测到 {0} 掉线" },
			{ "sos_target", "目标" },
			{ "sos_last", "上次" },
			{ "unknown", "未知" },
			{ "cache_snapshot", "[缓存快照]" },
			{ "seconds_ago", "秒前" },
			{ "majority_server", "多数派服务器:" },
			{ "not_connected", "未连接" },
			{ "history", "[历史]" },
			{ "notification_disconnected", "连接断开" },
			{ "manual_operation", "[系统] 手动操作..." },
			{ "state_synced", "同步" },
			{ "state_isolated", "孤立" },
			{ "state_connecting", "连接中" },
			{ "state_disconnected", "断开" },
			{ "state_connected", "已连接" },
			{ "state_mismatch", "错位" },
			{ "state_abnormal", "异常" },
			{ "state_unknown", "未知" },
			{ "state_left", "已退" },
			{ "state_status", "状态" },
			{ "cs_initializing", "初始化中..." },
			{ "cs_authenticating", "验证中..." },
			{ "cs_authenticated", "已验证" },
			{ "cs_joining", "加入中..." },
			{ "cs_joined", "已连接" },
			{ "cs_disconnecting", "断开中..." },
			{ "cs_disconnected", "断开" },
			{ "cs_connecting_game", "连接到游戏服务器中..." },
			{ "cs_connecting_master", "连接到主服务器中..." },
			{ "cs_connecting_name", "连接到名称服务器中..." },
			{ "detail_waiting_data", "(等待数据...)" },
			{ "detail_fetching", "获取中..." },
			{ "detail_connecting_to", "正在连接" },
			{ "detail_joined_voice", "已连入语音服" },
			{ "detail_connecting_local", "连接中..." },
			{ "detail_latency", "延迟" },
			{ "ls_joined", "已连接" },
			{ "ls_disconnected", "已断开" },
			{ "log_state_change", "状态变更" },
			{ "log_host_ip_change", "房主连接服务器变动" },
			{ "log_host_disconnected", "[Host] 房主意外断开,正在自动恢复..." },
			{ "log_loop_blind", "[循环] 已失败{0}次,暂时切换为盲连..." },
			{ "log_wrong_freq", "[异频] 当前:{0} 目标:{1} | 纠正({2}/2)" },
			{ "log_compromise", "[妥协] 纠正失败,驻留当前IP: {0}" },
			{ "log_reflect_fail", "无法反射设置服务器 IP" },
			{ "log_reflect_error", "反射失败" },
			{ "log_decision", "[决策] 目标变更" },
			{ "log_majority", "多数派({0}人)" },
			{ "log_host", "房主" },
			{ "log_auto_blind", "自动(盲连)" },
			{ "log_sos_send", "[SOS] 发送求救" },
			{ "log_sos_target", "目标" },
			{ "log_sos_local", "本机" },
			{ "log_sos_manual", "手动断开 (Manual)" },
			{ "log_sos_received", "收到 {0} SOS (目标:{1})" },
			{ "log_alt_k_disconnect", "[系统] Alt+K 手动断开" },
			{ "log_alt_k_reconnect", "[系统] Alt+K 强制重连" },
			{ "log_cache_snapshot", "[缓存快照] 记录数" },
			{ "cfg_cat_ui", "UI设置" },
			{ "cfg_cat_net", "网络设置" },
			{ "cfg_cat_adv", "高级与调试" },
			{ "cfg_ui_position", "选择UI面板显示在屏幕的哪一侧。" },
			{ "cfg_toggle_key", "切换语音面板显示的按键。" },
			{ "cfg_show_pro", "是否在面板中显示具体的已连接语音服务器IP地址和调试信息。" },
			{ "cfg_offset_x_r", "距离屏幕右边缘的水平距离。" },
			{ "cfg_offset_y_r", "距离屏幕上边缘的垂直距离。" },
			{ "cfg_offset_x_l", "距离屏幕左边缘的水平距离。" },
			{ "cfg_offset_y_l", "距离屏幕上边缘的垂直距离。" },
			{ "cfg_font_size", "面板文字的基础大小。" },
			{ "cfg_host_symbol", "显示在房主名字前的特殊符号。" },
			{ "cfg_timeout", "如果连接卡住,超过多少秒判定为断开。" },
			{ "cfg_retry_interval", "每次自动重连之间的冷却时间。" },
			{ "cfg_manual_reconnect", "允许按 Alt+K 强制断开或重连语音。" },
			{ "cfg_ghost_fix", "尝试从场景中搜寻名字以修复 Unknown 问题。" },
			{ "cfg_max_name_len", "显示名字的最大字符数。" },
			{ "cfg_latency_offset", "Ping值显示的水平像素偏移。" },
			{ "cfg_auto_hide", "当所有人连接正常时,自动隐藏简易模式的UI。" },
			{ "cfg_show_ping", "在简易模式下方显示本机延迟。" },
			{ "cfg_hide_menu", "打开ESC菜单时隐藏UI。" },
			{ "cfg_virtual_player", "添加一个假玩家用于测试UI布局。" },
			{ "cfg_virtual_name", "假玩家的名字。" },
			{ "cfg_language", "语言(重启游戏生效) | Language(Need restart)" },
			{ "cfgn_ui_position", "UI位置" },
			{ "cfgn_toggle_key", "详细UI切换键" },
			{ "cfgn_show_pro", "显示连接到的语音服务器IP和详细信息" },
			{ "cfgn_offset_x_r", "右侧边距" },
			{ "cfgn_offset_y_r", "顶部边距(右)" },
			{ "cfgn_offset_x_l", "左侧边距" },
			{ "cfgn_offset_y_l", "顶部边距(左)" },
			{ "cfgn_font_size", "字体大小" },
			{ "cfgn_host_symbol", "房主标记符号" },
			{ "cfgn_timeout", "重连超时时间 (s)" },
			{ "cfgn_retry_interval", "重试间隔 (s)" },
			{ "cfgn_manual_reconnect", "启用手动重置 (Alt+K)" },
			{ "cfgn_max_name_len", "最大名字长度" },
			{ "cfgn_latency_offset", "延迟对齐偏移量" },
			{ "cfgn_auto_hide", "自动隐藏简易UI" },
			{ "cfgn_show_ping", "简易模式显示Ping" },
			{ "cfgn_hide_menu", "ESC菜单界面时隐藏" },
			{ "cfgn_virtual_player", "启用虚拟玩家" },
			{ "cfgn_virtual_name", "虚拟玩家名字" },
			{ "cfgn_language", "语言 | Language" }
		};

		private static readonly Dictionary<string, string> EN = new Dictionary<string, string>
		{
			{ "ui_title", "Voice Detail Status" },
			{ "ui_debug_title", "Voice Fix Debug Console (Alt+J) | EvCode:186" },
			{ "btn_copy_all", "Copy All" },
			{ "btn_export", "Export" },
			{ "btn_clear", "Clear" },
			{ "btn_dump", "Dump Photon Player List" },
			{ "filter_all", "All" },
			{ "filter_local", "Local" },
			{ "client_not_connected", "Client not connected" },
			{ "voice_player_list", "Photon Player List" },
			{ "ghost_tag", "[Ghost]" },
			{ "exported_to", "Exported to" },
			{ "export_failed", "Failed" },
			{ "copied", "Copied" },
			{ "voice_single_player", "Local Voice: Single Player" },
			{ "voice_local", "Local Voice: " },
			{ "voice_connected", "Connected" },
			{ "voice_count", "Voice Connected: " },
			{ "id_mismatch", "ID Mismatched" },
			{ "local_ping", "Local Ping: " },
			{ "local_server", "Local Server:" },
			{ "host_server", "Host Server:" },
			{ "label_local", "Local" },
			{ "label_sync", "Sync:" },
			{ "label_abnormal", "Abnormal:" },
			{ "warn_majority", "⚠ [WARN] Majority ({0}) on another channel!" },
			{ "virtual_player", "Virtual Player 1" },
			{ "sos_snapshot", "[SOS Snapshot]" },
			{ "sos_majority", "Majority" },
			{ "sos_person", "" },
			{ "sos_detected", "Detected {0} disconnected" },
			{ "sos_target", "Target" },
			{ "sos_last", "Last" },
			{ "unknown", "Unknown" },
			{ "cache_snapshot", "[Cache Snapshot]" },
			{ "seconds_ago", "sec ago" },
			{ "majority_server", "Majority Server:" },
			{ "not_connected", "Not Connected" },
			{ "history", "[History]" },
			{ "notification_disconnected", "Disconnected" },
			{ "manual_operation", "[System] Manual operation..." },
			{ "state_synced", "Synced" },
			{ "state_isolated", "Isolated" },
			{ "state_connecting", "Connecting" },
			{ "state_disconnected", "Disconnected" },
			{ "state_connected", "Connected" },
			{ "state_mismatch", "Mismatched" },
			{ "state_abnormal", "Abnormal" },
			{ "state_unknown", "Unknown" },
			{ "state_left", "Left" },
			{ "state_status", "Status" },
			{ "cs_initializing", "Initializing..." },
			{ "cs_authenticating", "Authenticating..." },
			{ "cs_authenticated", "Authenticated" },
			{ "cs_joining", "Joining..." },
			{ "cs_joined", "Joined" },
			{ "cs_disconnecting", "Disconnecting..." },
			{ "cs_disconnected", "Disconnected" },
			{ "cs_connecting_game", "Connecting to game server..." },
			{ "cs_connecting_master", "Connecting to master server..." },
			{ "cs_connecting_name", "Connecting to name server..." },
			{ "detail_waiting_data", "(Waiting for data...)" },
			{ "detail_fetching", "Fetching..." },
			{ "detail_connecting_to", "Connecting to" },
			{ "detail_joined_voice", "Joined voice server" },
			{ "detail_connecting_local", "Connecting..." },
			{ "detail_latency", "Latency" },
			{ "ls_joined", "Connected" },
			{ "ls_disconnected", "Disconnected" },
			{ "log_state_change", "State change" },
			{ "log_host_ip_change", "Host server connection change" },
			{ "log_host_disconnected", "[Host] Unexpected disconnect, recovering..." },
			{ "log_loop_blind", "[Loop] Failed {0} times, switching to blind..." },
			{ "log_wrong_freq", "[WrongIP] Current:{0} Target:{1} | Fix({2}/2)" },
			{ "log_compromise", "[Compromise] Fix failed, staying on: {0}" },
			{ "log_reflect_fail", "Cannot set Server IP via reflection" },
			{ "log_reflect_error", "Reflection failed" },
			{ "log_decision", "[Decision] Target changed" },
			{ "log_majority", "Majority ({0})" },
			{ "log_host", "Host" },
			{ "log_auto_blind", "Auto (Blind)" },
			{ "log_sos_send", "[SOS] Sending SOS" },
			{ "log_sos_target", "Target" },
			{ "log_sos_local", "Local" },
			{ "log_sos_manual", "Manual Disconnect" },
			{ "log_sos_received", "Received {0} SOS (Target:{1})" },
			{ "log_alt_k_disconnect", "[System] Alt+K Manual disconnect" },
			{ "log_alt_k_reconnect", "[System] Alt+K Force reconnect" },
			{ "log_cache_snapshot", "[Cache Snapshot] Count" },
			{ "cfg_cat_ui", "UI Settings" },
			{ "cfg_cat_net", "Network Settings" },
			{ "cfg_cat_adv", "Advanced & Debug" },
			{ "cfg_ui_position", "Which side of the screen to display the UI panel." },
			{ "cfg_toggle_key", "Key to toggle voice panel display." },
			{ "cfg_show_pro", "Show connected voice server IP and debug info in the panel." },
			{ "cfg_offset_x_r", "Horizontal offset from right edge." },
			{ "cfg_offset_y_r", "Vertical offset from top edge." },
			{ "cfg_offset_x_l", "Horizontal offset from left edge." },
			{ "cfg_offset_y_l", "Vertical offset from top edge." },
			{ "cfg_font_size", "Base font size of the panel." },
			{ "cfg_host_symbol", "Symbol displayed before host's name." },
			{ "cfg_timeout", "Seconds before connection is deemed disconnected." },
			{ "cfg_retry_interval", "Cooldown between auto-reconnect attempts." },
			{ "cfg_manual_reconnect", "Allow Alt+K to force disconnect/reconnect voice." },
			{ "cfg_ghost_fix", "Try to find names from scene to fix Unknown issue." },
			{ "cfg_max_name_len", "Max display characters for names." },
			{ "cfg_latency_offset", "Horizontal pixel offset for ping display." },
			{ "cfg_auto_hide", "Auto-hide simple UI when all connections are normal." },
			{ "cfg_show_ping", "Show local ping below simple mode UI." },
			{ "cfg_hide_menu", "Hide UI when ESC menu is open." },
			{ "cfg_virtual_player", "Add a fake player for UI layout testing." },
			{ "cfg_virtual_name", "Name of the fake player." },
			{ "cfg_language", "语言(重启游戏生效) | Language(Need restart)" },
			{ "cfgn_ui_position", "UI Position" },
			{ "cfgn_toggle_key", "Toggle Key" },
			{ "cfgn_show_pro", "Show Server IP & Details" },
			{ "cfgn_offset_x_r", "Right Margin" },
			{ "cfgn_offset_y_r", "Top Margin (Right)" },
			{ "cfgn_offset_x_l", "Left Margin" },
			{ "cfgn_offset_y_l", "Top Margin (Left)" },
			{ "cfgn_font_size", "Font Size" },
			{ "cfgn_host_symbol", "Host Symbol" },
			{ "cfgn_timeout", "Reconnect Timeout (s)" },
			{ "cfgn_retry_interval", "Retry Interval (s)" },
			{ "cfgn_manual_reconnect", "Enable Manual Reset (Alt+K)" },
			{ "cfgn_max_name_len", "Max Name Length" },
			{ "cfgn_latency_offset", "Latency Alignment Offset" },
			{ "cfgn_auto_hide", "Auto-Hide Simple UI" },
			{ "cfgn_show_ping", "Show Ping in Simple Mode" },
			{ "cfgn_hide_menu", "Hide on ESC Menu" },
			{ "cfgn_virtual_player", "Enable Virtual Player" },
			{ "cfgn_virtual_name", "Virtual Player Name" },
			{ "cfgn_language", "语言 | Language" }
		};

		public static string DetectDefault()
		{
			CultureInfo currentUICulture = CultureInfo.CurrentUICulture;
			return currentUICulture.Name.StartsWith("zh") ? "中文" : "English";
		}

		public static void Init(string lang)
		{
			_lang = lang;
			_current = ((_lang == "中文") ? ZH : EN);
		}

		public static string Get(string key)
		{
			if (_current != null && _current.TryGetValue(key, out var value))
			{
				return value;
			}
			if (ZH.TryGetValue(key, out var value2))
			{
				return value2;
			}
			return key;
		}

		public static string Get(string key, params object[] args)
		{
			return string.Format(Get(key), args);
		}
	}
	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 static bool wasInRoom = false;

		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 voiceActorNumber)
		{
			if (PhotonNetwork.CurrentRoom == null)
			{
				return true;
			}
			if (PhotonNetwork.CurrentRoom.GetPlayer(voiceActorNumber, false) != null)
			{
				return false;
			}
			if ((Object)(object)punVoice == (Object)null || ((VoiceConnection)punVoice).Client == null || ((LoadBalancingClient)((VoiceConnection)punVoice).Client).CurrentRoom == null)
			{
				return true;
			}
			Dictionary<int, Player> players = ((LoadBalancingClient)((VoiceConnection)punVoice).Client).CurrentRoom.Players;
			if (!players.TryGetValue(voiceActorNumber, out var value))
			{
				return true;
			}
			string userId = value.UserId;
			if (string.IsNullOrEmpty(userId))
			{
				return true;
			}
			Player[] playerList = PhotonNetwork.PlayerList;
			foreach (Player val in playerList)
			{
				if (!string.IsNullOrEmpty(val.UserId) && val.UserId == userId)
				{
					return false;
				}
			}
			return true;
		}

		public static bool IsPlayerInVoiceRoom(int gameActorNumber)
		{
			if ((Object)(object)punVoice == (Object)null || ((VoiceConnection)punVoice).Client == null || ((LoadBalancingClient)((VoiceConnection)punVoice).Client).CurrentRoom == null)
			{
				return false;
			}
			if (PhotonNetwork.CurrentRoom == null)
			{
				return false;
			}
			Player player = PhotonNetwork.CurrentRoom.GetPlayer(gameActorNumber, false);
			if (player == null)
			{
				return false;
			}
			if (((LoadBalancingClient)((VoiceConnection)punVoice).Client).CurrentRoom.Players.ContainsKey(gameActorNumber))
			{
				return true;
			}
			string userId = player.UserId;
			if (string.IsNullOrEmpty(userId))
			{
				return false;
			}
			foreach (KeyValuePair<int, Player> player2 in ((LoadBalancingClient)((VoiceConnection)punVoice).Client).CurrentRoom.Players)
			{
				if (!string.IsNullOrEmpty(player2.Value.UserId) && player2.Value.UserId == userId)
				{
					return true;
				}
			}
			return false;
		}

		public static int GetGhostCount()
		{
			if ((Object)(object)punVoice == (Object)null || ((VoiceConnection)punVoice).Client == null || ((LoadBalancingClient)((VoiceConnection)punVoice).Client).CurrentRoom == null)
			{
				return 0;
			}
			if (PhotonNetwork.CurrentRoom != null && PhotonNetwork.CurrentRoom.PlayerCount <= 1)
			{
				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_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_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Invalid comparison between Unknown and I4
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)punVoice == (Object)null)
			{
				GameObject val = GameObject.Find("VoiceClient");
				if ((Object)(object)val != (Object)null)
				{
					punVoice = val.GetComponent<PunVoiceClient>();
				}
			}
			if (!PhotonNetwork.InRoom)
			{
				if (wasInRoom)
				{
					ResetRoomScopedState();
				}
				wasInRoom = false;
				return;
			}
			wasInRoom = true;
			if ((Object)(object)punVoice != (Object)null && ((VoiceConnection)punVoice).Client != null)
			{
				ClientState state = ((LoadBalancingClient)((VoiceConnection)punVoice).Client).State;
				if (state != lastClientState)
				{
					string message = string.Format("{0}: {1} -> {2}", L.Get("log_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,
				"v1.0.2"
			};
			RaiseEventOptions val = new RaiseEventOptions
			{
				Receivers = (ReceiverGroup)0
			};
			PhotonNetwork.RaiseEvent((byte)186, (object)array, val, SendOptions.SendUnreliable);
		}

		public static void BroadcastLog(string message)
		{
			//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_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			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, "v1.0.2");
			}
			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(string.Format("{0}:{1}", L.Get("log_cache_snapshot"), 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 = L.Get("log_host_ip_change") + ": " + 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
				{
					string playerName = GetPlayerName(sOSData.ActorNumber);
					if ((string.IsNullOrEmpty(playerName) || playerName == "Unknown" || playerName.StartsWith("Player ")) && (PhotonNetwork.CurrentRoom == null || PhotonNetwork.CurrentRoom.GetPlayer(sOSData.ActorNumber, false) == null))
					{
						ActiveSOSList.RemoveAt(num);
					}
					else if (PhotonNetwork.CurrentRoom != null)
					{
						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(L.Get("log_host_disconnected"));
				((VoiceConnection)punVoice).ConnectUsingSettings(PhotonNetwork.PhotonServerSettings.AppSettings);
				nextRetryTime = Time.unscaledTime + 5f;
			}
		}

		private static void HandleClientLogic()
		{
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Invalid comparison between Unknown and I4
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Invalid comparison between Unknown and I4
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Invalid comparison between Unknown and I4
			string mode;
			string text = DecideTargetIP(out mode);
			if (!string.IsNullOrEmpty(text) && ConnectionFailCount > 0 && ConnectionFailCount % 6 >= 3)
			{
				BroadcastLog(L.Get("log_loop_blind", ConnectionFailCount));
				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(L.Get("log_wrong_freq", gameServerAddress, TargetGameServer, WrongIPCount) ?? "");
					((LoadBalancingClient)((VoiceConnection)punVoice).Client).Disconnect();
					PerformReconnect(mode);
				}
				else if (WrongIPCount == 3)
				{
					BroadcastLog(L.Get("log_compromise", 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)L.Get("log_reflect_fail"));
				}
			}
			catch (Exception arg)
			{
				if (VoiceFix.logger != null)
				{
					VoiceFix.logger.LogError((object)string.Format("{0}: {1}", L.Get("log_reflect_error"), arg));
				}
			}
		}

		private static string DecideTargetIP(out string mode)
		{
			int maxCount;
			string majorityIP = GetMajorityIP(out maxCount);
			if (!string.IsNullOrEmpty(majorityIP) && maxCount >= 2)
			{
				mode = L.Get("log_majority", maxCount);
				ConnectedUsingHost = false;
				LogDecision(mode, majorityIP);
				return majorityIP;
			}
			if (!string.IsNullOrEmpty(LastKnownHostIP))
			{
				mode = L.Get("log_host");
				ConnectedUsingHost = true;
				LogDecision(mode, LastKnownHostIP);
				return LastKnownHostIP;
			}
			mode = L.Get("log_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(L.Get("log_decision") + ": " + 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_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Expected O, but got Unknown
			//IL_00d7: 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(L.Get("log_sos_send") + " -> " + L.Get("log_sos_target") + ":" + targetInfo + " | " + L.Get("log_sos_local") + ":" + 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", L.Get("log_sos_received", playerName, 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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Invalid comparison between Unknown and I4
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Invalid comparison between Unknown and I4
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: 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 ((Object)(object)punVoice == (Object)null || ((VoiceConnection)punVoice).Client == null)
			{
				BroadcastLog("[System] Alt+K ignored: Voice client not ready.");
				return;
			}
			if ((int)((LoadBalancingClient)((VoiceConnection)punVoice).Client).State == 9 || (int)((LoadBalancingClient)((VoiceConnection)punVoice).Client).State == 6 || (int)((LoadBalancingClient)((VoiceConnection)punVoice).Client).State == 1)
			{
				BroadcastLog(L.Get("log_alt_k_disconnect"));
				if (PhotonNetwork.IsConnectedAndReady)
				{
					SendSOS(L.Get("log_sos_manual"));
				}
				((LoadBalancingClient)((VoiceConnection)punVoice).Client).Disconnect();
				if ((Object)(object)VoiceUIManager.Instance != (Object)null)
				{
					VoiceUIManager.Instance.ShowStatsTemporary();
				}
			}
			else
			{
				BroadcastLog(L.Get("log_alt_k_reconnect"));
				SetGameServerAddress(ip: TargetGameServer = DecideTargetIP(out var _), client: (LoadBalancingClient)(object)((VoiceConnection)punVoice).Client);
				nextRetryTime = Time.unscaledTime;
				ConnectionFailCount = 0;
				((VoiceConnection)punVoice).ConnectUsingSettings(PhotonNetwork.PhotonServerSettings.AppSettings);
			}
			WrongIPCount = 0;
			TotalRetryCount = 0;
		}

		private static void ResetRoomScopedState()
		{
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			PlayerCache.Clear();
			ActiveSOSList.Clear();
			HostHistory.Clear();
			TargetGameServer = null;
			ConnectedUsingHost = true;
			IsBlindConnect = false;
			WrongIPCount = 0;
			ConnectionFailCount = 0;
			TotalRetryCount = 0;
			LastErrorMessage = "";
			LastKnownHostIP = "";
			LastHostUpdateTime = 0f;
			LastScanTime = 0f;
			LastDecisionLog = "";
			lastClientState = (ClientState)14;
			nextRetryTime = 0f;
			lastPingPublishTime = 0f;
			lastSOSTime = 0f;
			nextSummaryLogTime = 0f;
		}
	}
	[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 (methodName == "RemoveSkeletonRPC" && (int)target == 3)
			{
				target = (RpcTarget)0;
			}
		}
	}
	public enum UIPositionEnum
	{
		Left,
		Right
	}
	[BepInPlugin("chuxiaaaa.Aiae.BetterPeakVoiceFix", "BetterPeakVoiceFix", "1.0.2")]
	public class VoiceFix : BaseUnityPlugin
	{
		public static VoiceFix Instance;

		public static ManualLogSource logger;

		public static ManualLogSource debugLogger;

		public static ConfigEntry<string> Language;

		public static ConfigEntry<UIPositionEnum> UIPositionSide;

		public static ConfigEntry<string> 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<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> EnableVirtualTestPlayer;

		public static ConfigEntry<string> TestPlayerName;

		public const string PLUGIN_VERSION = "1.0.2";

		public const string MOD_VERSION = "v1.0.2";

		public static KeyCode GetToggleKey()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (Enum.TryParse<KeyCode>(ToggleUIKey.Value, ignoreCase: true, out KeyCode result))
			{
				return result;
			}
			return (KeyCode)106;
		}

		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_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Expected O, but got Unknown
			//IL_00b6: 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_0105: Expected O, but got Unknown
			//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f1: Expected O, but got Unknown
			Instance = this;
			logger = ((BaseUnityPlugin)this).Logger;
			debugLogger = new ManualLogSource("VoiceFixDebug");
			Logger.Sources.Add((ILogSource)(object)debugLogger);
			string text = L.DetectDefault();
			L.Init(text);
			Language = ((BaseUnityPlugin)this).Config.Bind<string>("Language", "语言-重启生效 | Language - need restart", text, new ConfigDescription(L.Get("cfg_language"), (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "中文", "English" }), Array.Empty<object>()));
			L.Init(Language.Value);
			string text2 = L.Get("cfg_cat_ui");
			ConfigFile config = ((BaseUnityPlugin)this).Config;
			string text3 = L.Get("cfgn_toggle_key");
			KeyCode val = (KeyCode)106;
			ToggleUIKey = config.Bind<string>(text2, text3, ((object)(KeyCode)(ref val)).ToString(), L.Get("cfg_toggle_key"));
			UIPositionSide = ((BaseUnityPlugin)this).Config.Bind<UIPositionEnum>(text2, L.Get("cfgn_ui_position"), UIPositionEnum.Right, new ConfigDescription(L.Get("cfg_ui_position"), (AcceptableValueBase)null, Array.Empty<object>()));
			ShowProfessionalInfo = ((BaseUnityPlugin)this).Config.Bind<bool>(text2, L.Get("cfgn_show_pro"), false, L.Get("cfg_show_pro"));
			OffsetX_Right = ((BaseUnityPlugin)this).Config.Bind<float>(text2, L.Get("cfgn_offset_x_r"), 20f, L.Get("cfg_offset_x_r"));
			OffsetY_Right = ((BaseUnityPlugin)this).Config.Bind<float>(text2, L.Get("cfgn_offset_y_r"), 20f, L.Get("cfg_offset_y_r"));
			OffsetX_Left = ((BaseUnityPlugin)this).Config.Bind<float>(text2, L.Get("cfgn_offset_x_l"), 20f, L.Get("cfg_offset_x_l"));
			OffsetY_Left = ((BaseUnityPlugin)this).Config.Bind<float>(text2, L.Get("cfgn_offset_y_l"), 20f, L.Get("cfg_offset_y_l"));
			FontSize = ((BaseUnityPlugin)this).Config.Bind<float>(text2, L.Get("cfgn_font_size"), 21f, L.Get("cfg_font_size"));
			HostSymbol = ((BaseUnityPlugin)this).Config.Bind<string>(text2, L.Get("cfgn_host_symbol"), "★", L.Get("cfg_host_symbol"));
			string text4 = L.Get("cfg_cat_net");
			ConnectTimeout = ((BaseUnityPlugin)this).Config.Bind<float>(text4, L.Get("cfgn_timeout"), 25f, L.Get("cfg_timeout"));
			RetryInterval = ((BaseUnityPlugin)this).Config.Bind<float>(text4, L.Get("cfgn_retry_interval"), 8f, L.Get("cfg_retry_interval"));
			EnableManualReconnect = ((BaseUnityPlugin)this).Config.Bind<bool>(text4, L.Get("cfgn_manual_reconnect"), true, L.Get("cfg_manual_reconnect"));
			string text5 = L.Get("cfg_cat_adv");
			MaxTotalLength = ((BaseUnityPlugin)this).Config.Bind<int>(text5, L.Get("cfgn_max_name_len"), 26, new ConfigDescription(L.Get("cfg_max_name_len"), (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 60), Array.Empty<object>()));
			LatencyOffset = ((BaseUnityPlugin)this).Config.Bind<float>(text5, L.Get("cfgn_latency_offset"), 350f, L.Get("cfg_latency_offset"));
			AutoHideNormal = ((BaseUnityPlugin)this).Config.Bind<bool>(text5, L.Get("cfgn_auto_hide"), true, L.Get("cfg_auto_hide"));
			ShowPingInNormal = ((BaseUnityPlugin)this).Config.Bind<bool>(text5, L.Get("cfgn_show_ping"), true, L.Get("cfg_show_ping"));
			HideOnMenu = ((BaseUnityPlugin)this).Config.Bind<bool>(text5, L.Get("cfgn_hide_menu"), true, L.Get("cfg_hide_menu"));
			EnableVirtualTestPlayer = ((BaseUnityPlugin)this).Config.Bind<bool>(text5, L.Get("cfgn_virtual_player"), false, L.Get("cfg_virtual_player"));
			TestPlayerName = ((BaseUnityPlugin)this).Config.Bind<string>(text5, L.Get("cfgn_virtual_name"), "1234567891012141618202224262830323436", L.Get("cfg_virtual_name"));
			Harmony.CreateAndPatchAll(typeof(LoadBalancingClientPatch), (string)null);
			Harmony.CreateAndPatchAll(typeof(PhotonRPCFix), (string)null);
			VoiceUIManager.CreateGlobalInstance();
			logger.LogInfo((object)"Better Voice Fix (v1.0.2) 已加载。");
		}

		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;

		private float lastJoinTimesCleanup = 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_006c: Expected O, but got Unknown
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			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), L.Get("ui_debug_title"));
			}
		}

		private void DrawDebugWindow(int windowID)
		{
			//IL_0099: 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_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0262: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0413: Unknown result type (might be due to invalid IL or missing references)
			//IL_0421: 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_0447: Invalid comparison between Unknown and I4
			//IL_045c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0462: Invalid comparison between Unknown and I4
			//IL_0369: Unknown result type (might be due to invalid IL or missing references)
			//IL_036e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0380: Expected O, but got Unknown
			//IL_0484: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a2: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button(L.Get("btn_copy_all"), Array.Empty<GUILayoutOption>()))
			{
				ExportLogs(toFile: false);
			}
			if (GUILayout.Button(L.Get("btn_export"), Array.Empty<GUILayoutOption>()))
			{
				ExportLogs(toFile: true);
			}
			if (GUILayout.Button(L.Get("btn_clear"), Array.Empty<GUILayoutOption>()))
			{
				debugLogs.Clear();
			}
			if (GUILayout.Button(L.Get("btn_dump"), 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) ? ("[★" + L.Get("filter_all") + "]") : L.Get("filter_all"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) }))
			{
				logFilterMode = 0;
			}
			if (GUILayout.Button((logFilterMode == 1) ? ("[★" + L.Get("filter_local") + "]") : L.Get("filter_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", L.Get("client_not_connected"), isLocal: true);
				return;
			}
			StringBuilder stringBuilder = new StringBuilder();
			Dictionary<int, Player> players = ((LoadBalancingClient)((VoiceConnection)NetworkManager.punVoice).Client).CurrentRoom.Players;
			stringBuilder.AppendLine(string.Format("=== {0} (Count: {1}) ===", L.Get("voice_player_list"), 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 ? (" " + L.Get("ghost_tag")) : "");
				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", L.Get("exported_to") + ": " + text, isLocal: true);
					return;
				}
				catch (Exception ex)
				{
					AddLog("System", L.Get("export_failed") + ": " + ex.Message, isLocal: true);
					return;
				}
			}
			GUIUtility.systemCopyBuffer = stringBuilder.ToString();
			AddLog("System", L.Get("copied"), isLocal: true);
		}

		private void Update()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			if (VoiceFix.ToggleUIKey == null)
			{
				return;
			}
			if (Input.GetKeyDown(VoiceFix.GetToggleKey()))
			{
				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;
			}
			CleanupJoinTimes();
			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;
					bool flag5 = VoiceFix.AutoHideNormal != null && VoiceFix.AutoHideNormal.Value && IsAllGood();
					if ((flag || flag4) && (!flag5 || 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_0101: 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_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: 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_00d6: 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 == UIPositionEnum.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(L.Get("notification_disconnected"), "#F0E68C");
			notificationExpiry = Time.unscaledTime + 5f;
		}

		public void ShowStatsTemporary()
		{
			notificationMsg = "<color=#F0E68C>" + L.Get("manual_operation") + "</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 L.Get("ls_disconnected");
				}
				return ((object)(ClientState)(ref state)).ToString();
			}
			return L.Get("ls_joined");
		}

		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 L.Get("state_synced");
				}
				if (joined == 1 && PhotonNetwork.CurrentRoom != null && PhotonNetwork.CurrentRoom.PlayerCount > 1)
				{
					color = "#F0E68C";
					return L.Get("state_isolated");
				}
				color = "#90EE90";
				return L.Get("state_synced");
			}
			if (IsConnectingLocal())
			{
				color = "#F0E68C";
				return L.Get("state_connecting");
			}
			color = "#FF6961";
			return L.Get("state_disconnected");
		}

		private void AppendCommonStats(StringBuilder sb, bool forceShow)
		{
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			bool flag = PhotonNetwork.OfflineMode || (PhotonNetwork.CurrentRoom != null && PhotonNetwork.CurrentRoom.PlayerCount <= 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>" + L.Get("voice_single_player") + "</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 != L.Get("state_synced") && myStateRaw != L.Get("state_isolated"))
					{
						text = GetLocalizedState(((LoadBalancingClient)((VoiceConnection)NetworkManager.punVoice).Client).State);
					}
					sb.Append("<color=#dfdac2>" + L.Get("voice_local") + "</color>");
					if (IsVoiceConnected())
					{
						if (PhotonNetwork.IsMasterClient)
						{
							sb.Append("<color=#dfdac2>" + L.Get("voice_connected") + "</color>");
						}
						else
						{
							sb.Append("<color=#dfdac2>" + L.Get("voice_connected") + "</color> " + FormatStatusTag(myStateRaw, color));
						}
					}
					else
					{
						sb.Append("<color=" + color + ">" + text + "</color>");
					}
					sb.Append("\n");
					GetVoiceCounts(out var joined, out var total);
					int ghostCount = NetworkManager.GetGhostCount();
					int num = joined + ghostCount;
					if ((Object)(object)NetworkManager.punVoice != (Object)null && ((VoiceConnection)NetworkManager.punVoice).Client != null && ((LoadBalancingClient)((VoiceConnection)NetworkManager.punVoice).Client).CurrentRoom != null)
					{
						num = ((LoadBalancingClient)((VoiceConnection)NetworkManager.punVoice).Client).CurrentRoom.Players.Count;
					}
					int num2 = total;
					sb.Append("<color=#dfdac2>" + L.Get("voice_count") + "</color>");
					string arg = "#F0E68C";
					if (num == 1 && num2 >= 3)
					{
						arg = "#FF6961";
					}
					else if (ghostCount > 0)
					{
						arg = "#b2d3b2";
					}
					else if (num == num2)
					{
						arg = "#90EE90";
					}
					sb.Append($"<color={arg}>{num}</color>");
					sb.Append(string.Format("<color={0}>/</color><color={1}>{2}</color>", "#dfdac2", "#dfdac2", num2));
					if (ghostCount > 0)
					{
						sb.Append(string.Format(" <color={0}>(</color><color={1}>{2}</color><color={3}> {4})</color>", "#dfdac2", "#b2d3b2", ghostCount, "#dfdac2", L.Get("id_mismatch")));
					}
					sb.Append("\n");
				}
				if (VoiceFix.ShowPingInNormal != null && VoiceFix.ShowPingInNormal.Value)
				{
					int ping = PhotonNetwork.GetPing();
					string text2 = ((ping < 100) ? "#90EE90" : ((ping < 200) ? "#F0E68C" : "#FF6961"));
					sb.Append(string.Format("<color={0}>{1}</color><color={2}>{3}ms</color>\n", "#dfdac2", L.Get("local_ping"), text2, 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>" + L.Get("ui_title") + " (v1.0.2)</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>" + L.Get("local_server") + "</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>" + L.Get("host_server") + "</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>" + L.Get("label_local") + "</color><color=#dfdac2>]</color> ");
				string text2 = ((joined >= total) ? "#90EE90" : "#F0E68C");
				stringBuilder.Append(string.Format("<color={0}>[</color><color={1}>{2}</color><color={3}>{4}/{5}</color><color={6}>]</color> ", "#dfdac2", "#dfdac2", L.Get("label_sync"), text2, joined, total, "#dfdac2"));
				string text3 = ((num > 0) ? "#CD5C5C" : "#dfdac2");
				stringBuilder.Append(string.Format("<color={0}>[</color><color={1}>{2}</color><color={3}>{4}</color><color={5}>]</color>", "#dfdac2", "#dfdac2", L.Get("label_abnormal"), text3, num, "#dfdac2"));
			}
			else
			{
				Player masterClient = PhotonNetwork.MasterClient;
				string s = ((masterClient != null) ? NetworkManager.GetPlayerName(masterClient.ActorNumber) : L.Get("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("<color=#F0E68C><size=85%>" + L.Get("warn_majority", c) + "</size></color>\n");
				}
			}
			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 = L.Get("virtual_player"),
					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 flag = false;
					flag = NetworkManager.IsPlayerInVoiceRoom(actorNumber);
					if (isLocal)
					{
						text5 = GetCurrentIP();
						ping = PhotonNetwork.GetPing();
						hasModData = true;
						flag = 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 = flag,
						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>" + L.Get("sos_snapshot") + "</color>\n");
				int c2;
				string majorityIP2 = GetMajorityIP(out c2);
				stringBuilder.Append(string.Format("<size=80%><color={0}>{1}: {2} ({3}{4})</color></size>\n", "#dfdac2", L.Get("sos_majority"), majorityIP2, c2, L.Get("sos_person")));
				foreach (SOSData activeSOS in NetworkManager.ActiveSOSList)
				{
					stringBuilder.Append("<size=80%><color=#FF6961>" + L.Get("sos_detected", activeSOS.PlayerName) + "</color></size>\n");
					string text6 = (string.IsNullOrEmpty(activeSOS.OriginIP) ? L.Get("unknown") : activeSOS.OriginIP);
					stringBuilder.Append("  <size=80%><color=#dfdac2>" + L.Get("sos_target") + ": (" + activeSOS.TargetIP + ") | " + L.Get("sos_last") + ": " + text6 + "</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}>{1} ({2:F0}{3})</color>\n", "#dfdac2", L.Get("cache_snapshot"), num2, L.Get("seconds_ago")));
				stringBuilder.Append(string.Format("<color={0}>{1}</color> <color={2}>{3}</color> <color={4}>({5}{6})</color>\n", "#dfdac2", L.Get("majority_server"), "#dfdac2", majorityIP3, "#dfdac2", c3, L.Get("sos_person")));
				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 text7 = (string.IsNullOrEmpty(item3.Key) ? L.Get("not_connected") : item3.Key);
						IEnumerable<string> values = item3.Select((KeyValuePair<int, CacheEntry> x) => x.Value.PlayerName).Take(3);
						string text8 = string.Join(",", values);
						stringBuilder.Append("<color=#dfdac2> - " + text7 + ": " + text8 + "</color>\n");
					}
				}
				if (NetworkManager.HostHistory.Count > 0)
				{
					stringBuilder.Append("<color=#dfdac2>" + L.Get("history") + "</color> " + NetworkManager.HostHistory[NetworkManager.HostHistory.Count - 1] + "\n");
				}
				stringBuilder.Append("</size>");
			}
			((TMP_Text)statsText).text = stringBuilder.ToString();
		}

		private string GetClientStateLocalized(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_004f: Expected I4, but got Unknown
			ClientState val = state;
			ClientState val2 = val;
			return (int)val2 switch
			{
				0 => L.Get("cs_initializing"), 
				1 => L.Get("cs_authenticating"), 
				2 => L.Get("cs_authenticated"), 
				8 => L.Get("cs_joining"), 
				9 => L.Get("cs_joined"), 
				13 => L.Get("cs_disconnecting"), 
				14 => L.Get("cs_disconnected"), 
				6 => L.Get("cs_connecting_game"), 
				12 => L.Get("cs_connecting_master"), 
				16 => L.Get("cs_connecting_name"), 
				_ => ((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_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Invalid comparison between Unknown and I4
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Invalid comparison between Unknown and I4
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Invalid comparison between Unknown and I4
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f4: 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 = L.Get("state_unknown");
				string colorHex = "#dfdac2";
				bool flag = false;
				string text3 = "";
				if (isInVoiceRoom)
				{
					text2 = L.Get("state_connected");
					colorHex = "#98FB98";
				}
				else if (remoteState != 0)
				{
					ClientState val = (ClientState)remoteState;
					if ((int)val == 14 || (int)val == 13)
					{
						text2 = L.Get("state_disconnected");
						colorHex = "#FF6961";
					}
					else if ((int)val == 9)
					{
						text2 = L.Get("state_connected");
						colorHex = "#98FB98";
					}
					else
					{
						text2 = L.Get("state_connecting");
						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;
					}
					float num2 = ((VoiceFix.ConnectTimeout != null) ? VoiceFix.ConnectTimeout.Value : 25f);
					if (Time.unscaledTime - joinTimes[actorNumber] < num2)
					{
						text2 = L.Get("state_connecting");
						colorHex = "#F0E68C";
					}
					else if (hasGhosts)
					{
						text2 = L.Get("state_mismatch");
						colorHex = "#b2d3b2";
					}
					else
					{
						text2 = L.Get("state_disconnected");
						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 = L.Get("state_connecting");
					text6 = "#F0E68C";
					flag3 = true;
					num = 8;
				}
				else
				{
					text5 = L.Get("state_disconnected");
					text6 = "#FF6961";
					num = 6;
				}
			}
			else if (IsIPMatch(ip))
			{
				text5 = L.Get("state_synced");
				text6 = "#90EE90";
				num = 6;
			}
			else
			{
				text5 = L.Get("state_abnormal");
				text6 = "#CD5C5C";
				num = 6;
			}
			if (isLocal)
			{
				num = 6;
				if (IsConnectingLocal())
				{
					flag3 = true;
				}
			}
			if (!isAlive && !isLocal)
			{
				text5 = L.Get("state_left");
				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>" + L.Get("label_local") + "</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}>| {2}:</color><color={3}>{4}ms</color>", alignX, "#dfdac2", L.Get("detail_latency"), text12, ping);
			}
			sb.Append(text7 + " " + text8 + "<size=100%><color=" + text10 + ">" + text9 + "</color></size>" + text11 + "\n");
			if (pro && !isLocal)
			{
				string text13 = ip;
				string text14 = L.Get("state_connected");
				if (remoteState != 0 && remoteState != 9 && remoteState != 14)
				{
					text13 = GetClientStateLocalized((ClientState)remoteState);
					text14 = L.Get("state_status");
					sb.Append("<voffset=0.17em><size=80%><color=#dfdac2>  » " + text13 + "</color></size></voffset>\n");
					return;
				}
				string text15 = (flag3 ? L.Get("detail_waiting_data") : (string.IsNullOrEmpty(ip) ? "N/A" : ip));
				if (flag3 && string.IsNullOrEmpty(ip))
				{
					text15 = "<color=grey>" + L.Get("detail_fetching") + "</color>";
				}
				string text16 = (flag3 ? L.Get("detail_connecting_to") : L.Get("detail_joined_voice"));
				sb.Append("<voffset=0.17em><size=80%><color=#dfdac2>  » " + text16 + ": " + text15 + "</color></size></voffset>\n");
			}
			else if (pro && isLocal && flag3)
			{
				string text17 = L.Get("detail_connecting_local");
				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 (total <= 1)
			{
				joined = (IsVoiceConnected() ? 1 : 0);
				return;
			}
			if ((Object)(object)NetworkManager.punVoice != (Object)null && ((VoiceConnection)NetworkManager.punVoice).Client != null && ((LoadBalancingClient)((VoiceConnection)NetworkManager.punVoice).Client).CurrentRoom != null)
			{
				foreach (KeyValuePair<int, Player> player in ((LoadBalancingClient)((VoiceConnection)NetworkManager.punVoice).Client).CurrentRoom.Players)
				{
					if (!NetworkManager.IsGhost(player.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()
		{
			if (!IsVoiceConnected() || IsMismatch() || NetworkManager.TotalRetryCount > 0)
			{
				return false;
			}
			GetVoiceCounts(out var joined, out var total);
			int ghostCount = NetworkManager.GetGhostCount();
			return joined >= total && ghostCount == 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 CleanupJoinTimes()
		{
			if (Time.unscaledTime - lastJoinTimesCleanup < 60f)
			{
				return;
			}
			lastJoinTimesCleanup = Time.unscaledTime;
			if (PhotonNetwork.CurrentRoom == null)
			{
				joinTimes.Clear();
				return;
			}
			List<int> list = new List<int>();
			foreach (KeyValuePair<int, float> joinTime in joinTimes)
			{
				if (PhotonNetwork.CurrentRoom.GetPlayer(joinTime.Key, false) == null)
				{
					list.Add(joinTime.Key);
				}
			}
			foreach (int item in list)
			{
				joinTimes.Remove(item);
			}
		}

		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)
		{
		}
	}
}

BepInEx/plugins/PEAKUnlimited.dll

Decompiled 6 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
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 HarmonyLib;
using Microsoft.CodeAnalysis;
using PEAKUnlimited.Configuration;
using PEAKUnlimited.Model.GameInfo;
using PEAKUnlimited.Patches;
using PEAKUnlimited.Util.Debugging;
using Peak.Network;
using Photon.Pun;
using Photon.Realtime;
using Steamworks;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.Utilities;
using UnityEngine.UI;
using Zorro.Core;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("PEAKUnlimited")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("3.7.0.0")]
[assembly: AssemblyInformationalVersion("3.7.0+bd53f0a09b7c9b6b0dbbedaf681e45eadbe54f61")]
[assembly: AssemblyProduct("PEAKUnlimited")]
[assembly: AssemblyTitle("PEAKUnlimited")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("3.7.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null)
		{
		}
	}
}
namespace PEAKUnlimited
{
	public class ConfigurationHandler
	{
		private ConfigFile _config;

		public static ConfigEntry<int> ConfigMaxPlayers;

		public ConfigEntry<bool> ConfigLockKiosk;

		public ConfigEntry<bool> ConfigLobbyDetails;

		public ConfigEntry<bool> ConfigExtraMarshmallows;

		public ConfigEntry<bool> ConfigLateMarshmallows;

		public ConfigEntry<int> ConfigCheatExtraMarshmallows;

		public ConfigEntry<bool> ConfigExtraBackpacks;

		public ConfigEntry<int> ConfigCheatExtraBackpacks;

		public ConfigEntry<string> ConfigVisibleLogTypes;

		public ConfigEntry<float> ConfigHotDogChance;

		public ConfigEntry<string> ConfigMenuKey;

		public InputAction MenuAction { get; set; }

		public int MaxPlayers => ConfigMaxPlayers.Value;

		public bool LockKiosk => ConfigLockKiosk.Value;

		public bool IsLobbyDetailsEnabled => ConfigLobbyDetails.Value;

		public bool IsExtraMarshmallowsEnabled => ConfigExtraMarshmallows.Value;

		public bool IsLateMarshmallowsEnabled => ConfigLateMarshmallows.Value;

		public int CheatMarshmallows => ConfigCheatExtraMarshmallows.Value;

		public bool IsExtraBackpacksEnabled => ConfigExtraBackpacks.Value;

		public string VisibleLogTypes => ConfigVisibleLogTypes.Value;

		public int CheatBackpacks => ConfigCheatExtraBackpacks.Value;

		public ConfigurationHandler(ConfigFile configFile)
		{
			_config = configFile;
			Plugin.Logger.LogInfo((object)"ConfigurationHandler initialising");
			ConfigMaxPlayers = _config.Bind<int>("General", "MaxPlayers", 20, "The maximum number of players you want to be able to join your lobby (Including yourself). Warning: untested, higher numbers may be unstable! Range: 1-20");
			if (ConfigMaxPlayers.Value == 0)
			{
				ConfigMaxPlayers.Value = 1;
			}
			else if (ConfigMaxPlayers.Value > 30)
			{
				ConfigMaxPlayers.Value = 30;
			}
			Plugin.Logger.LogInfo((object)("ConfigurationHandler: Max Players Loaded: " + ConfigMaxPlayers.Value));
			ConfigLockKiosk = _config.Bind<bool>("General", "LockKiosk", false, "Allows you to stop other players starting the game from the Airport Kiosk");
			Plugin.Logger.LogInfo((object)("ConfigurationHandler: Lock Kiosk enabled: " + ConfigLockKiosk.Value));
			ConfigLobbyDetails = _config.Bind<bool>("General", "LobbyDetails", true, "Prints the lobby details in the join log when a game is started");
			Plugin.Logger.LogInfo((object)("ConfigurationHandler: Lobby details enabled: " + ConfigLobbyDetails.Value));
			ConfigExtraMarshmallows = _config.Bind<bool>("General", "ExtraMarshmallows", true, "Controls whether additional marshmallows and hot dogs are spawned for the extra players");
			Plugin.Logger.LogInfo((object)("ConfigurationHandler: Extra marshmallows enabled: " + ConfigExtraMarshmallows.Value));
			ConfigHotDogChance = _config.Bind<float>("General", "HotDogChance", 0.375f, "Controls the chance of hot dogs being spawned instead of marshmallows for extra players, Range: 0-1");
			Plugin.Logger.LogInfo((object)("ConfigurationHandler: Hot dog chance set to: " + ConfigHotDogChance.Value));
			if (ConfigHotDogChance.Value < 0f)
			{
				ConfigHotDogChance.Value = 0f;
			}
			else if (ConfigHotDogChance.Value > 1f)
			{
				ConfigHotDogChance.Value = 1f;
			}
			ConfigExtraBackpacks = _config.Bind<bool>("General", "ExtraBackpacks", true, "Controls whether additional backpacks have a chance to be spawned for extra players");
			Plugin.Logger.LogInfo((object)("ConfigurationHandler: Extra backpacks enabled: " + ConfigExtraBackpacks.Value));
			ConfigVisibleLogTypes = _config.Bind<string>("General", "VisibleLogTypes", "", "Determines what types of debug messages are visible in the Bepinex Logs, Options include: " + string.Join(", ", Enum.GetNames(typeof(DebugLogType))));
			Plugin.Logger.LogInfo((object)("ConfigurationHandler: Log Types Enabled: " + string.Join(", ", Enum.GetNames(typeof(DebugLogType)))));
			ConfigLateMarshmallows = _config.Bind<bool>("General", "LateJoinMarshmallows", true, "Controls whether additional marshmallows are spawned for players who join late (mid run), and removed for those who leave early");
			Plugin.Logger.LogInfo((object)("ConfigurationHandler: Late Marshmallows enabled: " + ConfigLateMarshmallows.Value));
			ConfigCheatExtraMarshmallows = _config.Bind<int>("General", "Cheat Marshmallows", 0, "(Cheat, disabled by default) This will set the desired amount of marshmallows to the campfires as a cheat, requires ExtraMarshmallows to be enabled. Capped at 30.");
			if (ConfigCheatExtraMarshmallows.Value > 30)
			{
				ConfigCheatExtraMarshmallows.Value = 30;
			}
			else if (ConfigCheatExtraMarshmallows.Value < 0)
			{
				ConfigCheatExtraMarshmallows.Value = 0;
			}
			Plugin.Logger.LogInfo((object)("ConfigurationHandler: Cheat Marshmallows set to: " + ConfigCheatExtraMarshmallows.Value));
			ConfigMenuKey = _config.Bind<string>("General", "Config Menu Key", "<Keyboard>/f2", "Control path for opening the mod configuration menu (e.g. <Keyboard>/f2, <Keyboard>/space, <Keyboard>/escape)");
			Plugin.Logger.LogInfo((object)("ConfigurationHandler: Config Menu Key: " + ConfigMenuKey.Value));
			SetupInputAction();
			ConfigMenuKey.SettingChanged += OnMenuKeyChanged;
			ConfigCheatExtraBackpacks = _config.Bind<int>("General", "Cheat Backpacks", 0, "(Cheat, disabled by default) Sets how many backpacks will spawn as a cheat, requires ExtraBackpacks to also be enabled. Capped at 10.");
			if (ConfigCheatExtraBackpacks.Value > 10)
			{
				ConfigCheatExtraBackpacks.Value = 10;
			}
			else if (ConfigCheatExtraBackpacks.Value < 0)
			{
				ConfigCheatExtraBackpacks.Value = 0;
			}
			Plugin.Logger.LogInfo((object)("ConfigurationHandler: Cheat Backpacks set to: " + ConfigCheatExtraBackpacks.Value));
			Plugin.Logger.LogInfo((object)"ConfigurationHandler initialised");
		}

		private void OnMenuKeyChanged(object sender, EventArgs e)
		{
			SetupInputAction();
		}

		private void SetupInputAction()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			InputAction menuAction = MenuAction;
			if (menuAction != null)
			{
				menuAction.Dispose();
			}
			MenuAction = new InputAction((string)null, (InputActionType)1, (string)null, (string)null, (string)null, (string)null);
			InputActionSetupExtensions.AddBinding(MenuAction, ConfigMenuKey.Value, (string)null, (string)null, (string)null);
			MenuAction.Enable();
		}
	}
	[BepInPlugin("PEAKUnlimited", "PEAKUnlimited", "3.7.0")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Logger;

		public static ConfigurationHandler ConfigurationHandler;

		private readonly Harmony _harmony = new Harmony("PEAKUnlimited");

		public static List<Campfire> CampfireList = new List<Campfire>();

		public static bool IsAfterAwake = false;

		public const int VanillaMaxPlayers = 4;

		public static Dictionary<Campfire, List<GameObject>> Marshmallows = new Dictionary<Campfire, List<GameObject>>();

		public static bool HasHostStarted = false;

		private ModConfigurationUI _ui;

		public const string Id = "PEAKUnlimited";

		public static string Name => "PEAKUnlimited";

		public static string Version => "3.7.0";

		private void Awake()
		{
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Expected O, but got Unknown
			Logger = ((BaseUnityPlugin)this).Logger;
			Logger.LogInfo((object)"Plugin PEAKUnlimited is loaded!");
			ConfigurationHandler = new ConfigurationHandler(((BaseUnityPlugin)this).Config);
			UnlimitedLogger.GetInstance().DebugMessage((LogLevel)16, DebugLogType.PatchingLogic, "Plugin PEAKUnlimited set the Max Players to " + ConfigurationHandler.ConfigMaxPlayers.Value + "!");
			_harmony.PatchAll(typeof(NetworkingUtilitiesHostRoomOptionsPatch));
			_harmony.PatchAll(typeof(SteamLobbyHandlerSetLobbyDataPatch));
			_harmony.PatchAll(typeof(CampfireAwakePatch));
			_harmony.PatchAll(typeof(OnPlayerLeftRoomPatch));
			_harmony.PatchAll(typeof(OnPlayerEnteredRoomPatch));
			UnlimitedLogger.GetInstance().DebugMessage((LogLevel)16, DebugLogType.PatchingLogic, "Marshmallow patches successful!");
			_harmony.PatchAll(typeof(StartGamePatch));
			_harmony.PatchAll(typeof(LoadIslandMasterPatch));
			UnlimitedLogger.GetInstance().DebugMessage((LogLevel)16, DebugLogType.PatchingLogic, "Kiosk patches successful!");
			_harmony.PatchAll(typeof(EndSequenceRoutinePatch));
			_harmony.PatchAll(typeof(WaitingForPlayersUIPatch));
			_harmony.PatchAll(typeof(EndScreenStartPatch));
			_harmony.PatchAll(typeof(EndScreenNextPatch));
			UnlimitedLogger.GetInstance().DebugMessage((LogLevel)16, DebugLogType.PatchingLogic, "End screen patches successful!");
			_harmony.PatchAll(typeof(PlayerConnectionLogAwakePatch));
			_harmony.PatchAll(typeof(PlayClickedPatch));
			_harmony.PatchAll(typeof(LeaveLobbyPatch));
			UnlimitedLogger.GetInstance().DebugMessage((LogLevel)16, DebugLogType.PatchingLogic, "Player connection log patches successful!");
			_harmony.PatchAll(typeof(AssignMixerGroupPatch));
			UnlimitedLogger.GetInstance().DebugMessage((LogLevel)16, DebugLogType.PatchingLogic, "Audio patches successful!");
			_harmony.PatchAll(typeof(SingleItemSpawnerTrySpawnItemsPatch));
			UnlimitedLogger.GetInstance().DebugMessage((LogLevel)16, DebugLogType.PatchingLogic, "Item Spawner patches successful!");
			GameObject val = new GameObject("PEAKUnlimitedUI");
			Object.DontDestroyOnLoad((Object)(object)val);
			_ui = val.AddComponent<ModConfigurationUI>();
			_ui.Init(new List<Option>
			{
				Option.Int("Max Players", ConfigurationHandler.ConfigMaxPlayers, 1, 30, 1, () => PhotonNetwork.InRoom),
				Option.Bool("Extra Backpacks", ConfigurationHandler.ConfigExtraBackpacks, () => PhotonNetwork.InRoom && (int)GameHandler.GetService<RichPresenceService>()._presence.State != 1),
				Option.Bool("Extra Campfire Food", ConfigurationHandler.ConfigExtraMarshmallows, () => PhotonNetwork.InRoom && (int)GameHandler.GetService<RichPresenceService>()._presence.State != 1),
				Option.Float("Hot Dog Chance", ConfigurationHandler.ConfigHotDogChance, 0f, 1f, 0.005f, () => PhotonNetwork.InRoom && (int)GameHandler.GetService<RichPresenceService>()._presence.State != 1),
				Option.Bool("Late Join Campfire Food", ConfigurationHandler.ConfigLateMarshmallows, () => PhotonNetwork.InRoom && (int)GameHandler.GetService<RichPresenceService>()._presence.State != 1),
				Option.Bool("Host Locked Kiosk", ConfigurationHandler.ConfigLockKiosk, () => PhotonNetwork.InRoom && (int)GameHandler.GetService<RichPresenceService>()._presence.State != 1),
				Option.Bool("Lobby Details", ConfigurationHandler.ConfigLobbyDetails, () => PhotonNetwork.InRoom && (int)GameHandler.GetService<RichPresenceService>()._presence.State != 1),
				Option.Int("Cheat Campfire Food", ConfigurationHandler.ConfigCheatExtraMarshmallows, 0, 30, 1, () => PhotonNetwork.InRoom && (int)GameHandler.GetService<RichPresenceService>()._presence.State != 1),
				Option.Int("Cheat Backpacks", ConfigurationHandler.ConfigCheatExtraBackpacks, 0, 10, 1, () => PhotonNetwork.InRoom && (int)GameHandler.GetService<RichPresenceService>()._presence.State != 1),
				Option.InputAction("Menu Key", ConfigurationHandler.ConfigMenuKey)
			});
		}
	}
	public enum CampfireFoods
	{
		Marshmallow = 46,
		Glizzy = 154
	}
	public static class Utility
	{
		public static List<Vector3> GetEvenlySpacedPointsAroundCampfire(int numPoints, float innerRadius, float outerRadius, Vector3 campfirePosition, Vector3 campfireAngles, Segment advanceToSegment)
		{
			//IL_0007: 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_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_0065: 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_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: 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_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			List<Vector3> list = new List<Vector3>();
			Quaternion val = Quaternion.Euler(campfireAngles);
			Vector3 val2 = default(Vector3);
			for (int i = 0; i < numPoints; i++)
			{
				float num = outerRadius;
				if (i % 2 == 0)
				{
					num = innerRadius;
				}
				float num2 = (float)i * MathF.PI * 2f / (float)numPoints;
				float num3 = num * Mathf.Cos(num2);
				float num4 = num * Mathf.Sin(num2);
				((Vector3)(ref val2))..ctor(num3, 0f, num4);
				Vector3 val3 = val * val2;
				Vector3 val4 = campfirePosition + val3;
				val4.y += -0.05f;
				Vector3 val5 = SetToGround(val4);
				if (Vector3.Distance(val4, val5) <= 1f)
				{
					val4 = val5;
				}
				list.Add(val4);
			}
			return list;
		}

		public static List<GameObject> SpawnMarshmallows(int number, Vector3 campfirePosition, Vector3 campfireAngles, Segment advanceToSegment)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: 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_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			List<GameObject> list = new List<GameObject>();
			foreach (Vector3 item in GetEvenlySpacedPointsAroundCampfire(number, 2f, 2.5f, campfirePosition, campfireAngles, advanceToSegment))
			{
				float num = Random.Range(0f, 1f);
				float value = Plugin.ConfigurationHandler.ConfigHotDogChance.Value;
				CampfireFoods campfireFoods = ((!(num < value)) ? CampfireFoods.Marshmallow : CampfireFoods.Glizzy);
				ushort key = (ushort)campfireFoods;
				Item val = SingletonAsset<ItemDatabase>.Instance.itemLookup[key];
				val.GetName();
				Vector3 val2 = campfirePosition - item;
				Vector3 normalized = ((Vector3)(ref val2)).normalized;
				Quaternion val3 = Quaternion.LookRotation(normalized, Vector3.up);
				val3 *= Quaternion.Euler(0f, Random.Range(-30f, -150f), 0f);
				list.Add(((Component)Add(val, item, val3)).gameObject);
			}
			return list;
		}

		private static Vector3 SetToGround(Vector3 vector)
		{
			//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_000d: 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)
			return HelperFunctions.GetGroundPos(vector, (LayerType)1, 0f);
		}

		public static Item Add(Item item, Vector3 position, Quaternion rotation)
		{
			//IL_0024: 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_0046: Unknown result type (might be due to invalid IL or missing references)
			if (!PhotonNetwork.IsConnected)
			{
				return null;
			}
			UnlimitedLogger.GetInstance().DebugMessage((LogLevel)16, DebugLogType.CampfireLogic, $"Spawn item: {((Object)item).name} at {position}");
			return PhotonNetwork.Instantiate("0_Items/" + ((Object)item).name, position, rotation, (byte)0, (object[])null).GetComponent<Item>();
		}
	}
}
namespace PEAKUnlimited.Util.Debugging
{
	public enum DebugLogType
	{
		MarshmallowLogic,
		CampfireLogic,
		BackpackLogic,
		NetworkingLogic,
		PatchingLogic,
		EndScreenLogic
	}
	public class UnlimitedLogger
	{
		private static UnlimitedLogger _instance;

		private HashSet<DebugLogType> logTypeMap = new HashSet<DebugLogType>();

		public static UnlimitedLogger GetInstance()
		{
			if (_instance == null)
			{
				_instance = new UnlimitedLogger();
			}
			return _instance;
		}

		private UnlimitedLogger()
		{
			string visibleLogTypes = Plugin.ConfigurationHandler.VisibleLogTypes;
			string[] array = visibleLogTypes.Split(new string[1] { ", " }, StringSplitOptions.None);
			string[] array2 = array;
			foreach (string text in array2)
			{
				if (Enum.TryParse<DebugLogType>(text, ignoreCase: true, out var result))
				{
					logTypeMap.Add(result);
				}
				else
				{
					Console.WriteLine("Invalid enum name: " + text);
				}
			}
		}

		public void DebugMessage(LogLevel logLevel, DebugLogType logType, string message)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (logTypeMap.Contains(logType))
			{
				Plugin.Logger.Log(logLevel, (object)("[" + logType.ToString() + "]: " + message));
			}
		}
	}
}
namespace PEAKUnlimited.Patches
{
	public class AssignMixerGroupPatch
	{
		[HarmonyPatch(typeof(PlayerHandler), "AssignMixerGroup")]
		[HarmonyPrefix]
		private static bool Prefix(ref byte __result, Character character)
		{
			for (byte b = 0; b < ConfigurationHandler.ConfigMaxPlayers.Value; b++)
			{
				if (!PlayerHandler.Instance.m_assignedVoiceGroups.ContainsKey(b) || !ClassExtensionsMethods.UnityObjectExists<Character>(PlayerHandler.Instance.m_assignedVoiceGroups[b]))
				{
					PlayerHandler.Instance.m_assignedVoiceGroups[b] = character;
					__result = b;
					return false;
				}
			}
			__result = byte.MaxValue;
			return false;
		}
	}
	public class CampfireAwakePatch
	{
		[HarmonyPatch(typeof(Campfire), "Awake")]
		[HarmonyPostfix]
		private static void Postfix(Campfire __instance)
		{
			UnlimitedLogger.GetInstance().DebugMessage((LogLevel)16, DebugLogType.CampfireLogic, $"Campfire Awake Patch! Number of known campfires: {Plugin.CampfireList.Count}");
			UnlimitedLogger.GetInstance().DebugMessage((LogLevel)16, DebugLogType.CampfireLogic, new CampfireInfo().GetInfoMessage(__instance));
			if (PhotonNetwork.IsMasterClient && !(__instance.nameOverride == "NAME_PORTABLE STOVE"))
			{
				if (Plugin.ConfigurationHandler.IsExtraBackpacksEnabled)
				{
					AddBackpacks(__instance);
				}
				AddMarshmallows(__instance);
				Plugin.IsAfterAwake = true;
			}
		}

		private static void AddMarshmallows(Campfire __instance)
		{
			//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_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: 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)
			if (PhotonNetwork.IsMasterClient && !((Object)((Component)((Component)__instance).gameObject.transform.parent).gameObject).name.ToLower().Contains("wings"))
			{
				Plugin.CampfireList.Add(__instance);
				int num = Math.Min(4, PhotonNetwork.CurrentRoom.PlayerCount);
				if (Plugin.ConfigurationHandler.IsExtraMarshmallowsEnabled)
				{
					UnlimitedLogger.GetInstance().DebugMessage((LogLevel)16, DebugLogType.MarshmallowLogic, "Marshmallowification enabled and starting!");
					num = PhotonNetwork.CurrentRoom.PlayerCount;
				}
				if (Plugin.ConfigurationHandler.CheatMarshmallows != 0)
				{
					num = Plugin.ConfigurationHandler.CheatMarshmallows;
					UnlimitedLogger.GetInstance().DebugMessage((LogLevel)16, DebugLogType.MarshmallowLogic, "Cheatmallows enabled!");
				}
				UnlimitedLogger.GetInstance().DebugMessage((LogLevel)16, DebugLogType.MarshmallowLogic, $"Will spawn {num} marshmallows for {PhotonNetwork.CurrentRoom.PlayerCount} people!");
				Vector3 position = ((Component)__instance).gameObject.transform.position;
				Vector3 eulerAngles = ((Component)__instance).gameObject.transform.eulerAngles;
				Plugin.Marshmallows.Add(__instance, Utility.SpawnMarshmallows(num, position, eulerAngles, __instance.advanceToSegment));
			}
		}

		private static void AddBackpacks(Campfire __instance)
		{
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			UnlimitedLogger.GetInstance().DebugMessage((LogLevel)16, DebugLogType.BackpackLogic, "Backpackification enabled and starting!");
			Item item = SingletonAsset<ItemDatabase>.Instance.itemLookup[6];
			int num = PhotonNetwork.CurrentRoom.PlayerCount - 4;
			int num2 = 0;
			if (num > 0)
			{
				double num3 = (double)num * 0.25;
				if (num3 % 4.0 == 0.0)
				{
					num2 = (int)num3;
				}
				else
				{
					num2 = (int)num3;
					if ((double)Random.Range(0f, 1f) <= num3 - (double)num2)
					{
						num2++;
					}
				}
			}
			if (Plugin.ConfigurationHandler.CheatBackpacks != 0)
			{
				UnlimitedLogger.GetInstance().DebugMessage((LogLevel)16, DebugLogType.BackpackLogic, "Cheat Backpacks enabled = " + Plugin.ConfigurationHandler.CheatBackpacks);
				num2 = Plugin.ConfigurationHandler.CheatBackpacks - 1;
			}
			UnlimitedLogger.GetInstance().DebugMessage((LogLevel)16, DebugLogType.BackpackLogic, "Backpacks enabled = " + num2);
			if (num2 > 0)
			{
				foreach (Vector3 item2 in Utility.GetEvenlySpacedPointsAroundCampfire(num2, 3.3f, 3.7f, ((Component)__instance).gameObject.transform.position, ((Component)__instance).gameObject.transform.eulerAngles, __instance.advanceToSegment))
				{
					Vector3 position = item2;
					if (((Object)((Component)((Component)__instance).gameObject.transform.parent).gameObject).name.ToLower().Contains("wings"))
					{
						position = item2 + new Vector3(0f, 10f, 0f);
					}
					Quaternion rotation = Quaternion.Euler(0f, Random.Range(0f, 360f), 0f);
					((Component)Utility.Add(item, position, rotation)).transform.parent = ((Component)__instance).gameObject.transform;
				}
				return;
			}
			UnlimitedLogger.GetInstance().DebugMessage((LogLevel)16, DebugLogType.BackpackLogic, "Not enough players to add additional backpacks, use the Cheat Backpack configuration setting if you want to override this!");
		}
	}
	public class EndScreenNextPatch
	{
		[HarmonyPatch(typeof(EndScreen), "Next")]
		[HarmonyPostfix]
		private static void PostFix()
		{
			if (PhotonNetwork.IsMasterClient)
			{
				Plugin.CampfireList.Clear();
				Singleton<PeakHandler>.Instance.EndScreenComplete();
			}
		}
	}
	public class EndScreenStartPatch : MonoBehaviour
	{
		[HarmonyPatch(typeof(EndScreen), "Start")]
		[HarmonyPrefix]
		private static void Prefix(EndScreen __instance)
		{
			int playerCount = PhotonNetwork.CurrentRoom.PlayerCount;
			if (playerCount <= 4)
			{
				return;
			}
			EndScreenScoutWindow[] array = (EndScreenScoutWindow[])(object)new EndScreenScoutWindow[playerCount];
			Image[] array2 = (Image[])(object)new Image[playerCount];
			Image[] array3 = (Image[])(object)new Image[playerCount];
			Image[] array4 = (Image[])(object)new Image[playerCount];
			Transform[] array5 = (Transform[])(object)new Transform[playerCount];
			for (int i = 0; i < playerCount; i++)
			{
				if (i >= __instance.scouts.Length)
				{
					if ((Object)(object)__instance.scoutWindows[0] == (Object)null)
					{
						array[i] = null;
					}
					else
					{
						array[i] = Object.Instantiate<EndScreenScoutWindow>(__instance.scoutWindows[0], ((Component)__instance.scoutWindows[0]).transform.parent);
					}
					if ((Object)(object)__instance.scouts[0] == (Object)null)
					{
						array2[i] = null;
					}
					else
					{
						array2[i] = Object.Instantiate<Image>(__instance.scouts[0], ((Component)__instance.scouts[0]).transform.parent);
					}
					if ((Object)(object)__instance.scoutsAtPeak[0] == (Object)null)
					{
						array3[i] = null;
					}
					else
					{
						array3[i] = Object.Instantiate<Image>(__instance.scoutsAtPeak[0], ((Component)__instance.scoutsAtPeak[0]).transform.parent);
					}
					if ((Object)(object)__instance.oldPip[0] == (Object)null)
					{
						array4[i] = null;
					}
					else
					{
						array4[i] = Object.Instantiate<Image>(__instance.oldPip[0], ((Component)__instance.oldPip[0]).transform.parent);
					}
					if ((Object)(object)__instance.scoutLines[0] == (Object)null)
					{
						array5[i] = null;
					}
					else
					{
						array5[i] = Object.Instantiate<Transform>(__instance.scoutLines[0], ((Component)__instance.scoutLines[0]).transform.parent);
					}
				}
				else
				{
					array[i] = __instance.scoutWindows[i];
					array2[i] = __instance.scouts[i];
					array3[i] = __instance.scoutsAtPeak[i];
					array4[i] = __instance.oldPip[i];
					array5[i] = __instance.scoutLines[i];
				}
			}
			__instance.scoutWindows = array;
			__instance.scouts = array2;
			__instance.scoutsAtPeak = array3;
			__instance.oldPip = array4;
			__instance.scoutLines = array5;
		}
	}
	public class EndSequenceRoutinePatch : MonoBehaviour
	{
		[HarmonyPatch(typeof(EndScreen), "EndSequenceRoutine")]
		[HarmonyPostfix]
		private static void Postfix(EndScreen __instance)
		{
			for (int i = 4; i < Character.AllCharacters.Count; i++)
			{
				UnlimitedLogger.GetInstance().DebugMessage((LogLevel)16, DebugLogType.EndScreenLogic, "Deactivating an end screen");
				Object.Destroy((Object)(object)((Component)__instance.scoutWindows[i]).gameObject);
				UnlimitedLogger.GetInstance().DebugMessage((LogLevel)16, DebugLogType.EndScreenLogic, "Deleted an end screen");
			}
		}
	}
	public class LeaveLobbyPatch
	{
		[HarmonyPatch(typeof(SteamLobbyHandler), "LeaveLobby")]
		[HarmonyPostfix]
		private static void Postfix(SteamLobbyHandler __instance)
		{
			UnlimitedLogger.GetInstance().DebugMessage((LogLevel)16, DebugLogType.NetworkingLogic, "Left Lobby");
			PlayerConnectionLogAwakePatch.isHost = false;
		}
	}
	public class LoadIslandMasterPatch
	{
		[HarmonyPatch(typeof(AirportCheckInKiosk), "LoadIslandMaster")]
		[HarmonyPrefix]
		private static bool Prefix()
		{
			if (Plugin.ConfigurationHandler.LockKiosk)
			{
				bool flag = !PhotonNetwork.IsMasterClient || !Plugin.HasHostStarted;
				UnlimitedLogger.GetInstance().DebugMessage((LogLevel)16, DebugLogType.NetworkingLogic, $"Host Only Kiosk Logic being tested: Should Cancel Island Load = {flag}");
				if (!PhotonNetwork.IsMasterClient || !Plugin.HasHostStarted)
				{
					return false;
				}
			}
			Plugin.HasHostStarted = false;
			return true;
		}
	}
	public class NetworkingUtilitiesHostRoomOptionsPatch
	{
		[HarmonyPatch(typeof(NetworkingUtilities), "HostRoomOptions")]
		[HarmonyPrefix]
		private static bool Prefix(ref RoomOptions __result)
		{
			//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_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			__result = new RoomOptions
			{
				IsVisible = false,
				MaxPlayers = ConfigurationHandler.ConfigMaxPlayers.Value,
				PublishUserId = true
			};
			return false;
		}
	}
	public class OnPlayerEnteredRoomPatch
	{
		[HarmonyPatch(typeof(PlayerConnectionLog), "OnPlayerEnteredRoom")]
		[HarmonyPostfix]
		private static void Postfix()
		{
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			UnlimitedLogger.GetInstance().DebugMessage((LogLevel)16, DebugLogType.NetworkingLogic, "Someone has joined the room! Number: " + PhotonNetwork.CurrentRoom.PlayerCount + "/" + ConfigurationHandler.ConfigMaxPlayers.Value);
			if (!Plugin.ConfigurationHandler.IsLateMarshmallowsEnabled || Plugin.CampfireList == null || Plugin.CampfireList.Count == 0)
			{
				return;
			}
			Segment val;
			try
			{
				val = Singleton<MapHandler>.Instance.GetCurrentSegment();
			}
			catch (Exception ex)
			{
				UnlimitedLogger.GetInstance().DebugMessage((LogLevel)2, DebugLogType.NetworkingLogic, "Error getting current segment: " + ex);
				val = (Segment)0;
			}
			if (!Plugin.IsAfterAwake || !PhotonNetwork.IsMasterClient || Plugin.ConfigurationHandler.CheatMarshmallows != 0)
			{
				return;
			}
			foreach (KeyValuePair<Campfire, List<GameObject>> marshmallow in Plugin.Marshmallows)
			{
				if (marshmallow.Key.advanceToSegment <= val)
				{
					continue;
				}
				foreach (GameObject item in marshmallow.Value)
				{
					PhotonNetwork.Destroy(item);
				}
			}
			Plugin.Marshmallows.Clear();
			foreach (Campfire campfire in Plugin.CampfireList)
			{
				if (campfire.advanceToSegment > val)
				{
					Plugin.Marshmallows.Add(campfire, Utility.SpawnMarshmallows(PhotonNetwork.CurrentRoom.PlayerCount, ((Component)campfire).transform.position, ((Component)campfire).gameObject.transform.eulerAngles, campfire.advanceToSegment));
				}
			}
		}
	}
	public class OnPlayerLeftRoomPatch : MonoBehaviour
	{
		[HarmonyPatch(typeof(PlayerConnectionLog), "OnPlayerLeftRoom")]
		[HarmonyPostfix]
		private static void Postfix()
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: 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_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			UnlimitedLogger.GetInstance().DebugMessage((LogLevel)16, DebugLogType.NetworkingLogic, "Someone has left the room! Number: " + PhotonNetwork.CurrentRoom.PlayerCount + "/" + ConfigurationHandler.ConfigMaxPlayers.Value);
			if (!Plugin.ConfigurationHandler.IsLateMarshmallowsEnabled || Plugin.CampfireList == null || Plugin.CampfireList.Count == 0)
			{
				return;
			}
			Segment currentSegment = Singleton<MapHandler>.Instance.GetCurrentSegment();
			if (!Plugin.IsAfterAwake || !PhotonNetwork.IsMasterClient || Plugin.ConfigurationHandler.CheatMarshmallows != 0)
			{
				return;
			}
			foreach (KeyValuePair<Campfire, List<GameObject>> marshmallow in Plugin.Marshmallows)
			{
				if (marshmallow.Key.advanceToSegment <= currentSegment)
				{
					continue;
				}
				foreach (GameObject item in marshmallow.Value)
				{
					PhotonNetwork.Destroy(item);
				}
			}
			Plugin.Marshmallows.Clear();
			foreach (Campfire campfire in Plugin.CampfireList)
			{
				if (campfire.advanceToSegment > currentSegment)
				{
					Plugin.Marshmallows.Add(campfire, Utility.SpawnMarshmallows(PhotonNetwork.CurrentRoom.PlayerCount, ((Component)campfire).transform.position, ((Component)campfire).gameObject.transform.eulerAngles, campfire.advanceToSegment));
				}
			}
		}
	}
	public class PlayClickedPatch
	{
		[HarmonyPatch(typeof(MainMenuMainPage), "PlayClicked")]
		[HarmonyPostfix]
		private static void Postfix(MainMenuMainPage __instance)
		{
			Plugin.CampfireList.Clear();
			UnlimitedLogger.GetInstance().DebugMessage((LogLevel)16, DebugLogType.NetworkingLogic, "Play clicked, this player is the lobby host!");
			PlayerConnectionLogAwakePatch.isHost = true;
		}
	}
	public class PlayerConnectionLogAwakePatch
	{
		public static bool isHost;

		[HarmonyPatch(typeof(PlayerConnectionLog), "Awake")]
		[HarmonyPostfix]
		private static void Postfix(PlayerConnectionLog __instance)
		{
			//IL_002e: 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_02f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0306: 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_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: 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_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0216: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			if (!isHost || (Object)(object)GameObject.Find("AirportGateKiosk") == (Object)null)
			{
				return;
			}
			__instance.AddMessage(__instance.GetColorTag(__instance.joinedColor) + " Lobby started with: </color>" + __instance.GetColorTag(__instance.userColor) + " PEAK Unlimited </color>");
			if (Plugin.ConfigurationHandler.IsLobbyDetailsEnabled)
			{
				__instance.AddMessage($"{__instance.GetColorTag(__instance.joinedColor)} Max players: </color>{__instance.GetColorTag(__instance.userColor)} {ConfigurationHandler.ConfigMaxPlayers.Value} </color>");
				string text = "Enabled";
				if (!Plugin.ConfigurationHandler.IsExtraMarshmallowsEnabled)
				{
					text = "Disabled";
				}
				__instance.AddMessage(__instance.GetColorTag(__instance.joinedColor) + " Extra marshmallows: </color>" + __instance.GetColorTag(__instance.userColor) + " " + text + " </color>");
				text = "Enabled";
				if (!Plugin.ConfigurationHandler.IsExtraBackpacksEnabled)
				{
					text = "Disabled";
				}
				__instance.AddMessage(__instance.GetColorTag(__instance.joinedColor) + " Extra backpacks: </color>" + __instance.GetColorTag(__instance.userColor) + " " + text + " </color>");
				text = "Enabled";
				if (!Plugin.ConfigurationHandler.IsLateMarshmallowsEnabled)
				{
					text = "Disabled";
				}
				__instance.AddMessage(__instance.GetColorTag(__instance.joinedColor) + " Late join marshmallows: </color>" + __instance.GetColorTag(__instance.userColor) + " " + text + " </color>");
				text = "Enabled";
				if (!Plugin.ConfigurationHandler.LockKiosk)
				{
					text = "Disabled";
				}
				__instance.AddMessage(__instance.GetColorTag(__instance.joinedColor) + " Host only kiosk: </color>" + __instance.GetColorTag(__instance.userColor) + " " + text + " </color>");
				if (Plugin.ConfigurationHandler.CheatMarshmallows > 0)
				{
					__instance.AddMessage($"{__instance.GetColorTag(__instance.joinedColor)} Cheat marshmallows: </color>{__instance.GetColorTag(__instance.userColor)} {Plugin.ConfigurationHandler.CheatMarshmallows} </color>");
				}
				if (Plugin.ConfigurationHandler.CheatBackpacks > 0)
				{
					__instance.AddMessage($"{__instance.GetColorTag(__instance.joinedColor)} Cheat backpacks: </color>{__instance.GetColorTag(__instance.userColor)} {Plugin.ConfigurationHandler.CheatBackpacks} </color>");
				}
			}
			__instance.AddMessage(__instance.GetColorTag(__instance.joinedColor) + " Configure PEAK Unlimited with: </color>" + __instance.GetColorTag(__instance.userColor) + " F2 </color>");
		}
	}
	public class SingleItemSpawnerTrySpawnItemsPatch
	{
		[HarmonyPatch(typeof(Spawner), "TrySpawnItems")]
		[HarmonyPrefix]
		private static bool Prefix(ref List<PhotonView> __result, Spawner __instance)
		{
			if (((Object)((Component)__instance).gameObject).name == "CampfireFoodSpawner")
			{
				__result = new List<PhotonView>();
				return false;
			}
			return true;
		}
	}
	public class StartGamePatch
	{
		[HarmonyPatch(typeof(AirportCheckInKiosk), "StartGame")]
		[HarmonyPrefix]
		private static void Prefix()
		{
			if (PhotonNetwork.IsMasterClient)
			{
				Plugin.HasHostStarted = true;
			}
		}
	}
	public class SteamLobbyHandlerSetLobbyDataPatch
	{
		[HarmonyPatch(typeof(SteamLobbyHandler), "SetLobbyData")]
		[HarmonyPostfix]
		private static void Postfix(SteamLobbyHandler __instance)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			Plugin.Logger.LogInfo((object)("Setting lobby member limit to " + ConfigurationHandler.ConfigMaxPlayers.Value));
			SteamMatchmaking.SetLobbyMemberLimit(__instance.m_currentLobby, ConfigurationHandler.ConfigMaxPlayers.Value);
		}
	}
	public class WaitingForPlayersUIPatch : MonoBehaviour
	{
		[HarmonyPatch(typeof(WaitingForPlayersUI), "Update")]
		[HarmonyPrefix]
		private static void Prefix(WaitingForPlayersUI __instance)
		{
			if (__instance.scoutImages.Length >= Character.AllCharacters.Count)
			{
				return;
			}
			Image[] array = (Image[])(object)new Image[Character.AllCharacters.Count];
			Image val = __instance.scoutImages[0];
			for (int i = 0; i < Character.AllCharacters.Count; i++)
			{
				if (i < 4)
				{
					array[i] = __instance.scoutImages[i];
				}
				else
				{
					array[i] = Object.Instantiate<Image>(val, ((Component)val).transform.parent);
				}
			}
			__instance.scoutImages = array;
		}
	}
}
namespace PEAKUnlimited.Model.GameInfo
{
	public class CampfireInfo : IGameInfo<Campfire>
	{
		public string GetInfoMessage(Campfire gameInstance)
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine("Campfire Info:");
			stringBuilder.AppendLine("- Next Segment: " + ((object)(Segment)(ref gameInstance.advanceToSegment)).ToString());
			stringBuilder.AppendLine($"- Lit: {gameInstance.Lit}");
			return stringBuilder.ToString();
		}
	}
	public interface IGameInfo<T>
	{
		string GetInfoMessage(T gameInstance);
	}
}
namespace PEAKUnlimited.Configuration
{
	public class ModConfigurationUI : MonoBehaviour
	{
		private List<Option> _options;

		private bool _visible;

		private int _selectedIndex;

		private bool _prevCursorVisible;

		private CursorLockMode _prevCursorLock;

		private bool _waitingForBinding = false;

		private Option _bindingTarget;

		private Texture2D _whiteTex;

		private GUIStyle _titleStyle;

		private GUIStyle _rowStyle;

		private GUIStyle _hintStyle;

		private string titleText = "PEAK Unlimited Settings | v" + Plugin.Version;

		private string hintText = "F2: Open/Close • Tab or ↑/↓:  Move • Enter/Click: Change • Scroll Wheel or ←/→ Arrows: Adjust Numerical Values • +/-: Scale Menu";

		private int RowHeight = 32;

		private int PanelWidth = 460;

		private int Pad = 12;

		private int TitleFontSize = 22;

		private int OptionFontSize = 16;

		private int HintFontSize = 14;

		private void CalculatePanelWidth()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_0012: 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_0060: Expected O, but got Unknown
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			float num = _titleStyle.CalcSize(new GUIContent(titleText)).x;
			foreach (Option option in _options)
			{
				float x = _rowStyle.CalcSize(new GUIContent(option.Label + ": " + option.DisplayValue())).x;
				if (x > num)
				{
					num = x;
				}
			}
			int num2 = CalculateHintWidth();
			num = Mathf.Max(num, (float)num2);
			PanelWidth = Mathf.Clamp((int)num + Pad * 2, 460, Screen.width - Pad * 2);
		}

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

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

		public void Init(List<Option> options)
		{
			_options = options ?? new List<Option>();
			_selectedIndex = 0;
			hintText = Plugin.ConfigurationHandler.ConfigMenuKey.Value.Split("/")[^1].ToUpper() + ": Open/Close • Tab or ↑/↓:  Move • Enter/Click: Change • Scroll Wheel or ←/→ Arrows: Adjust Numerical Values • +/-: Scale Menu";
		}

		private void EnsureStyles()
		{
			//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_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: 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_0096: 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_00a7: Expected O, but got Unknown
			//IL_00ad: Expected O, but got Unknown
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Expected O, but got Unknown
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_whiteTex == (Object)null)
			{
				_whiteTex = new Texture2D(1, 1);
				_whiteTex.SetPixel(0, 0, Color.white);
				_whiteTex.Apply();
			}
			_titleStyle = new GUIStyle(GUI.skin.label)
			{
				fontSize = TitleFontSize,
				alignment = (TextAnchor)3,
				fontStyle = (FontStyle)1
			};
			_rowStyle = new GUIStyle(GUI.skin.button)
			{
				alignment = (TextAnchor)3,
				fontSize = OptionFontSize,
				padding = new RectOffset(10, 10, 4, 4)
			};
			_hintStyle = new GUIStyle(GUI.skin.label)
			{
				fontSize = HintFontSize,
				alignment = (TextAnchor)3,
				wordWrap = true
			};
		}

		private void Update()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Invalid comparison between Unknown and I4
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			if (_waitingForBinding && ((ButtonControl)Keyboard.current.anyKey).wasPressedThisFrame)
			{
				Enumerator<KeyControl> enumerator = Keyboard.current.allKeys.GetEnumerator();
				try
				{
					while (enumerator.MoveNext())
					{
						KeyControl current = enumerator.Current;
						if (((ButtonControl)current).wasPressedThisFrame)
						{
							string path = ((InputControl)current).path;
							_bindingTarget.StringEntry.Value = path;
							Plugin.Logger.LogInfo((object)("Rebound " + _bindingTarget.Label + " to " + path));
							_waitingForBinding = false;
							hintText = _bindingTarget.DisplayValue() + ": Open/Close • Tab or ↑/↓:  Move • Enter/Click: Change • Scroll Wheel or ←/→ Arrows: Adjust Numerical Values • +/-: Scale Menu";
							_bindingTarget = null;
							break;
						}
					}
					return;
				}
				finally
				{
					((IDisposable)enumerator).Dispose();
				}
			}
			if (Plugin.ConfigurationHandler.MenuAction != null && Plugin.ConfigurationHandler.MenuAction.WasPerformedThisFrame() && (PlayerConnectionLogAwakePatch.isHost || (int)GameHandler.GetService<RichPresenceService>()._presence.State == 0))
			{
				_visible = !_visible;
				if (_visible)
				{
					OnOpened();
				}
				else
				{
					OnClosed();
				}
			}
			if (_visible && _options.Count != 0)
			{
				if (Input.GetKeyDown((KeyCode)9))
				{
					bool flag = Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303);
					CycleSelection((!flag) ? 1 : (-1));
				}
				if (Input.GetKeyDown((KeyCode)61) || Input.GetKeyDown((KeyCode)43))
				{
					Scale(1);
				}
				if (Input.GetKeyDown((KeyCode)45))
				{
					Scale(-1);
				}
				if (Input.GetKeyDown((KeyCode)273))
				{
					CycleSelection(-1);
				}
				if (Input.GetKeyDown((KeyCode)274))
				{
					CycleSelection(1);
				}
				if (Input.GetKeyDown((KeyCode)13) || Input.GetKeyDown((KeyCode)271))
				{
					ToggleSelected();
				}
				if (Input.GetKeyDown((KeyCode)276))
				{
					AdjustNumerical(-1);
				}
				if (Input.GetKeyDown((KeyCode)275))
				{
					AdjustNumerical(1);
				}
				float y = ((InputControl<Vector2>)(object)Mouse.current.scroll).ReadValue().y;
				if (y > 0f)
				{
					AdjustNumerical(1);
				}
				else if (y < 0f)
				{
					AdjustNumerical(-1);
				}
			}
		}

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

		private void AdjustNumerical(int delta)
		{
			Option option = _options[_selectedIndex];
			if (!option.IsDisabled())
			{
				if (option.Type == Option.OptionType.Int)
				{
					int value = Mathf.Clamp(option.IntEntry.Value + delta * option.Step, option.MinInt, option.MaxInt);
					option.IntEntry.Value = value;
				}
				else if (option.Type == Option.OptionType.Float)
				{
					float value2 = Mathf.Clamp(option.FloatEntry.Value + (float)delta * option.FloatStep, option.MinFloat, option.MaxFloat);
					option.FloatEntry.Value = value2;
				}
			}
		}

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

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

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

		private void OnGUI()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_0384: Unknown result type (might be due to invalid IL or missing references)
			//IL_0398: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0229: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_028f: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			if (!_visible)
			{
				return;
			}
			EnsureStyles();
			CalculatePanelWidth();
			float num = _titleStyle.CalcHeight(new GUIContent(titleText), (float)(PanelWidth - Pad * 2));
			float num2 = _options.Count * (RowHeight + 4);
			float num3 = _hintStyle.CalcHeight(new GUIContent("Test"), 9999f);
			float num4 = num3 * 2f;
			int num5 = Pad + (int)num + 8 + (int)num2 + Pad + (int)num4;
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(20f, 20f, (float)PanelWidth, (float)num5);
			GUI.color = new Color(0f, 0f, 0f, 0.75f);
			GUI.DrawTexture(val, (Texture)(object)_whiteTex);
			GUI.color = Color.white;
			Rect val2 = default(Rect);
			((Rect)(ref val2))..ctor(((Rect)(ref val)).x + (float)Pad, ((Rect)(ref val)).y + (float)Pad, ((Rect)(ref val)).width - (float)(Pad * 2), num);
			GUI.Label(val2, titleText, _titleStyle);
			float num6 = ((Rect)(ref val2)).yMax + 8f;
			Rect val3 = default(Rect);
			for (int i = 0; i < _options.Count; i++)
			{
				((Rect)(ref val3))..ctor(((Rect)(ref val)).x + (float)Pad, num6, ((Rect)(ref val)).width - (float)(Pad * 2), (float)RowHeight);
				Option option = _options[i];
				if (((Rect)(ref val3)).Contains(Event.current.mousePosition) && !option.IsDisabled())
				{
					_selectedIndex = i;
				}
				if ((i == _selectedIndex && !option.IsDisabled()) || !(option.Label == "Menu Key") || !_waitingForBinding)
				{
					GUI.color = new Color(1f, 1f, 1f, 0.24f);
					GUI.DrawTexture(val3, (Texture)(object)_whiteTex);
					GUI.color = Color.white;
				}
				GUI.enabled = !option.IsDisabled();
				if (option.Label == "Menu Key" && _waitingForBinding)
				{
					GUI.color = new Color(0f, 0f, 0f, 0.6f);
					GUI.DrawTexture(val3, (Texture)(object)_whiteTex);
					GUI.color = Color.white;
					GUI.Button(val3, "Press any key...", _rowStyle);
				}
				else if (GUI.Button(val3, option.Label + ": " + option.DisplayValue(), _rowStyle) && !option.IsDisabled())
				{
					ToggleSelected();
				}
				GUI.enabled = true;
				num6 += (float)(RowHeight + 4);
			}
			Rect val4 = default(Rect);
			((Rect)(ref val4))..ctor(((Rect)(ref val)).x + (float)Pad, ((Rect)(ref val)).yMax - (float)Pad - num4, ((Rect)(ref val)).width - (float)(Pad * 2), num4);
			GUI.Label(val4, hintText, _hintStyle);
			GUI.Label(val4, hintText, _hintStyle);
		}

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

		public string Label { get; set; }

		public OptionType Type { get; set; }

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

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

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

		public int MinInt { get; set; }

		public int MaxInt { get; set; }

		public int Step { get; set; }

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


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


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

		public float MinFloat { get; set; }

		public float MaxFloat { get; set; }

		public float FloatStep { get; set; }

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

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

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

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

		public static Option Int(string label, ConfigEntry<int> entry, int min, int max, int step = 1, Func<bool>? isDisabled = null)
		{
			return new Option(label, OptionType.Int)
			{
				IntEntry = entry,
				MinInt = min,
				MaxInt = max,
				Step = step,
				IsDisabled = (isDisabled ?? ((Func<bool>)(() => false))),
				DisplayValue = () => entry.Value.ToString()
			};
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}