Decompiled source of PastaClient v0.0.4

PastaClient.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
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 System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using PastaClient.Patches;
using TMPro;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;
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: IgnoresAccessChecksTo("0Harmony")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("BepInEx")]
[assembly: IgnoresAccessChecksTo("BepInEx.Harmony")]
[assembly: IgnoresAccessChecksTo("LethalConfig")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem")]
[assembly: IgnoresAccessChecksTo("Unity.Netcode.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")]
[assembly: IgnoresAccessChecksTo("UnityEngine.IMGUIModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UI")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("PastaClient")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("made by Asta")]
[assembly: AssemblyFileVersion("1.2.1.0")]
[assembly: AssemblyInformationalVersion("1.2.1+8ac91082f94a2d3dda6e6ee3d9e2dde8fa02fc8c")]
[assembly: AssemblyProduct("PastaClient")]
[assembly: AssemblyTitle("PastaClient")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.1.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 PastaClient
{
	public static class ConfigManager
	{
		public static ConfigEntry<bool> EnableAutoKick;

		public static ConfigEntry<int> VoteKickThreshold;

		public static ConfigEntry<bool> EnableShitterUIOnKick;

		public static ConfigEntry<string> ServerUrl;

		public static void Init(ConfigFile cfg)
		{
			EnableAutoKick = cfg.Bind<bool>("General", "EnableAutoKick", true, "자동킥 활성화");
			VoteKickThreshold = cfg.Bind<int>("General", "VoteKickThreshold", 2, "자동킥 받을 투표 수");
			EnableShitterUIOnKick = cfg.Bind<bool>("General", "EnableShitterUIOnKick", true, "킥당했을 때 UI 띄우기");
			ServerUrl = cfg.Bind<string>("Server", "ServerUrl", "https://shitter.asta.rs", "서버 URL");
		}
	}
	public class PastaNetwork : NetworkBehaviour
	{
		private static HashSet<ulong> _previousClients = new HashSet<ulong>();

		private static HashSet<ulong> _processedConnects = new HashSet<ulong>();

		private static HashSet<ulong> _processedDisconnects = new HashSet<ulong>();

		public static PastaNetwork Instance { get; private set; } = null;


		public static void Init()
		{
			//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("PastaNetwork");
			Instance = val.AddComponent<PastaNetwork>();
			Object.DontDestroyOnLoad((Object)(object)val);
			((Object)val).hideFlags = (HideFlags)61;
			SteamNameFetcher.Init((MonoBehaviour)(object)Instance);
			ServerClient.Init((MonoBehaviour)(object)Instance);
		}

		private void Start()
		{
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)"[PastaNetwork] Start() called");
			}
			((MonoBehaviour)Instance).StartCoroutine(RegisterNetworkCallbacks());
			((MonoBehaviour)Instance).StartCoroutine(MonitorPlayerChanges());
		}

		private IEnumerator RegisterNetworkCallbacks()
		{
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)"[PastaNetwork] Waiting for NetworkManager to initialize...");
			}
			float timeout = 10f;
			float elapsed = 0f;
			while ((Object)(object)NetworkManager.Singleton == (Object)null && elapsed < timeout)
			{
				yield return (object)new WaitForSeconds(0.1f);
				elapsed += 0.1f;
			}
			if ((Object)(object)NetworkManager.Singleton == (Object)null)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)"[PastaNetwork] NetworkManager not found after timeout! Will monitor manually.");
				}
				yield break;
			}
			ManualLogSource log3 = Plugin.Log;
			if (log3 != null)
			{
				log3.LogInfo((object)"[PastaNetwork] NetworkManager found! Registering callbacks...");
			}
			try
			{
				NetworkManager.Singleton.OnClientConnectedCallback += OnClientConnected;
				NetworkManager.Singleton.OnClientDisconnectCallback += OnClientDisconnected;
				ManualLogSource log4 = Plugin.Log;
				if (log4 != null)
				{
					log4.LogInfo((object)"[PastaNetwork] Callbacks registered successfully!");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log5 = Plugin.Log;
				if (log5 != null)
				{
					log5.LogError((object)$"[PastaNetwork] Failed to register callbacks: {ex}");
				}
			}
		}

		private IEnumerator MonitorPlayerChanges()
		{
			yield return (object)new WaitForSeconds(2f);
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)"[PastaNetwork] 백업 플레이어 모니터링 시작... (서버/클라이언트 모두 지원)");
			}
			if ((Object)(object)NetworkManager.Singleton != (Object)null && !NetworkManager.Singleton.IsServer)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogInfo((object)"[PastaNetwork] 클라이언트 모드: 이미 있는 플레이어들 초기 수집 중...");
				}
				HashSet<ulong> initialPlayers = new HashSet<ulong>();
				for (int attempt = 0; attempt < 5; attempt++)
				{
					yield return (object)new WaitForSeconds(1f);
					try
					{
						PlayerControllerB[] allPlayers = Object.FindObjectsByType<PlayerControllerB>((FindObjectsSortMode)0);
						ManualLogSource log3 = Plugin.Log;
						if (log3 != null)
						{
							log3.LogInfo((object)$"[PastaNetwork] 초기 수집 시도 {attempt + 1}/5: PlayerControllerB {((allPlayers != null) ? allPlayers.Length : 0)}개 발견");
						}
						if (allPlayers != null)
						{
							PlayerControllerB[] array = allPlayers;
							foreach (PlayerControllerB player in array)
							{
								if (!((Object)(object)player != (Object)null) || player.actualClientId == 0)
								{
									continue;
								}
								ulong steamId = SteamIDHelper.GetSteamID(player.actualClientId);
								if (steamId != 0L && steamId != player.actualClientId)
								{
									initialPlayers.Add(steamId);
									ManualLogSource log4 = Plugin.Log;
									if (log4 != null)
									{
										log4.LogInfo((object)$"[PastaNetwork] 초기 발견된 플레이어: clientId={player.actualClientId}, steamId={steamId}");
									}
								}
								else if (steamId > 76561190000000000L && steamId < 76561199999999999L)
								{
									initialPlayers.Add(steamId);
									ManualLogSource log5 = Plugin.Log;
									if (log5 != null)
									{
										log5.LogInfo((object)$"[PastaNetwork] 초기 발견된 플레이어 (Steam ID 형식): {steamId}");
									}
								}
							}
						}
						if (attempt >= 2 && initialPlayers.Count > 0)
						{
							ManualLogSource log6 = Plugin.Log;
							if (log6 != null)
							{
								log6.LogInfo((object)$"[PastaNetwork] 플레이어 수집 완료 (시도 {attempt + 1}): {initialPlayers.Count}명");
							}
							break;
						}
						continue;
					}
					catch (Exception ex)
					{
						ManualLogSource log7 = Plugin.Log;
						if (log7 != null)
						{
							log7.LogError((object)$"[PastaNetwork] 초기 플레이어 수집 실패 (시도 {attempt + 1}): {ex.Message}");
						}
						continue;
					}
				}
				if (initialPlayers.Count > 0)
				{
					ManualLogSource log8 = Plugin.Log;
					if (log8 != null)
					{
						log8.LogInfo((object)$"[PastaNetwork] 총 초기 플레이어 {initialPlayers.Count}명 발견! KickTracker에 저장 중...");
					}
					KickTracker.SetCurrentPlayers(initialPlayers);
					foreach (ulong playerId in initialPlayers)
					{
						if (playerId != 0)
						{
							((MonoBehaviour)Instance).StartCoroutine(CachePlayerNameDelayed(playerId));
						}
					}
				}
				else
				{
					ManualLogSource log9 = Plugin.Log;
					if (log9 != null)
					{
						log9.LogWarning((object)"[PastaNetwork] 초기 플레이어를 찾지 못했습니다.");
					}
				}
			}
			while (true)
			{
				yield return (object)new WaitForSeconds(0.5f);
				if ((Object)(object)NetworkManager.Singleton == (Object)null)
				{
					continue;
				}
				HashSet<ulong> currentClients = new HashSet<ulong>();
				if (NetworkManager.Singleton.IsServer)
				{
					try
					{
						foreach (KeyValuePair<ulong, NetworkClient> kvp in NetworkManager.Singleton.ConnectedClients)
						{
							currentClients.Add(kvp.Key);
						}
					}
					catch (Exception ex4)
					{
						Exception ex2 = ex4;
						ManualLogSource log10 = Plugin.Log;
						if (log10 != null)
						{
							log10.LogWarning((object)("[PastaNetwork] ConnectedClients 접근 오류: " + ex2.Message));
						}
					}
				}
				try
				{
					PlayerControllerB[] allPlayers2 = Object.FindObjectsByType<PlayerControllerB>((FindObjectsSortMode)0);
					PlayerControllerB[] array2 = allPlayers2;
					foreach (PlayerControllerB player2 in array2)
					{
						if ((Object)(object)player2 != (Object)null && player2.actualClientId != 0)
						{
							ulong steamId2 = SteamIDHelper.GetSteamID(player2.actualClientId);
							if (steamId2 != 0)
							{
								currentClients.Add(steamId2);
							}
						}
					}
				}
				catch (Exception ex3)
				{
					ManualLogSource log11 = Plugin.Log;
					if (log11 != null)
					{
						log11.LogWarning((object)("[PastaNetwork] PlayerControllerB 찾기 오류: " + ex3.Message));
					}
				}
				foreach (ulong clientId2 in _previousClients)
				{
					if (!currentClients.Contains(clientId2) && !_processedDisconnects.Contains(clientId2))
					{
						_processedDisconnects.Add(clientId2);
						OnClientDisconnected(clientId2);
					}
				}
				foreach (ulong clientId in currentClients)
				{
					if (_previousClients.Contains(clientId) || _processedConnects.Contains(clientId) || clientId == 0)
					{
						continue;
					}
					_processedConnects.Add(clientId);
					ulong actualClientId = clientId;
					if (clientId > 76561190000000000L && clientId < 76561199999999999L && (Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsServer)
					{
						foreach (KeyValuePair<ulong, NetworkClient> connectedClient in NetworkManager.Singleton.ConnectedClients)
						{
							ulong connectedClientId = connectedClient.Key;
							ulong connectedSteamId = SteamIDHelper.GetSteamID(connectedClientId);
							if (connectedSteamId == clientId)
							{
								actualClientId = connectedClientId;
								break;
							}
						}
					}
					OnClientConnected(actualClientId);
				}
				_processedDisconnects.RemoveWhere((ulong id) => !_previousClients.Contains(id));
				_processedConnects.RemoveWhere((ulong id) => !currentClients.Contains(id));
				_previousClients = currentClients;
			}
		}

		private static void OnClientConnected(ulong clientId)
		{
			((MonoBehaviour)Instance).StartCoroutine(CachePlayerNameDelayed(clientId));
			if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsServer && (Object)(object)Instance != (Object)null && ((NetworkBehaviour)Instance).IsSpawned)
			{
				((MonoBehaviour)Instance).StartCoroutine(SendPlayerListToClient(clientId));
			}
			if ((Object)(object)NetworkManager.Singleton != (Object)null && !NetworkManager.Singleton.IsServer && clientId == NetworkManager.Singleton.LocalClientId)
			{
				((MonoBehaviour)Instance).StartCoroutine(CollectExistingPlayers());
			}
			if (!((Object)(object)NetworkManager.Singleton == (Object)null) && NetworkManager.Singleton.IsHost)
			{
				((MonoBehaviour)Instance).StartCoroutine(CheckAndKickPlayerDelayed(clientId));
			}
		}

		private static IEnumerator CollectExistingPlayers()
		{
			for (int attempt = 0; attempt < 5; attempt++)
			{
				yield return (object)new WaitForSeconds(1f);
				if ((Object)(object)NetworkManager.Singleton == (Object)null || NetworkManager.Singleton.IsServer)
				{
					yield break;
				}
				List<ulong> playerIds = new List<ulong>();
				try
				{
					PlayerControllerB[] allPlayers = Object.FindObjectsByType<PlayerControllerB>((FindObjectsSortMode)0);
					PlayerControllerB[] array = (PlayerControllerB[])(((object)allPlayers) ?? ((object)new PlayerControllerB[0]));
					foreach (PlayerControllerB player in array)
					{
						if ((Object)(object)player != (Object)null && player.actualClientId != 0)
						{
							ulong steamId = SteamIDHelper.GetSteamID(player.actualClientId);
							if (steamId != 0)
							{
								playerIds.Add(steamId);
							}
						}
					}
					if (playerIds.Count <= 0)
					{
						continue;
					}
					KickTracker.SetCurrentPlayers(playerIds);
					foreach (ulong playerId in playerIds)
					{
						if (playerId != 0)
						{
							((MonoBehaviour)Instance).StartCoroutine(CachePlayerNameDelayed(playerId));
						}
					}
					yield break;
				}
				catch (Exception ex)
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogError((object)$"[PastaNetwork] 플레이어 수집 실패 (시도 {attempt + 1}): {ex.Message}");
					}
				}
			}
			ManualLogSource log2 = Plugin.Log;
			if (log2 != null)
			{
				log2.LogWarning((object)"[PastaNetwork] 모든 시도 후에도 플레이어를 찾지 못했습니다.");
			}
		}

		private static IEnumerator SendPlayerListToClient(ulong clientId)
		{
			yield return (object)new WaitForSeconds(1f);
			if ((Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsServer || (Object)(object)Instance == (Object)null || !((NetworkBehaviour)Instance).IsSpawned)
			{
				yield break;
			}
			List<ulong> playerIds = new List<ulong>();
			try
			{
				foreach (KeyValuePair<ulong, NetworkClient> connectedClient in NetworkManager.Singleton.ConnectedClients)
				{
					ulong connectedClientId = connectedClient.Key;
					ulong steamId = SteamIDHelper.GetSteamID(connectedClientId);
					if (steamId != 0)
					{
						playerIds.Add(steamId);
					}
				}
				ClientRpcParams clientRpcParams = new ClientRpcParams
				{
					Send = new ClientRpcSendParams
					{
						TargetClientIds = new ulong[1] { clientId }
					}
				};
				Instance.SendPlayerListClientRpc(playerIds.ToArray(), clientRpcParams);
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)("[PastaNetwork] 플레이어 목록 전송 실패: " + ex.Message));
				}
			}
		}

		private static IEnumerator CachePlayerNameDelayed(ulong clientId)
		{
			yield return (object)new WaitForSeconds(1f);
			string playerName = GetPlayerName(clientId);
			if (!string.IsNullOrEmpty(playerName) && playerName != "Unknown")
			{
				RecentLeaveTracker.CachePlayerName(clientId, playerName);
			}
		}

		private static string GetPlayerName(ulong clientId)
		{
			if ((Object)(object)NetworkManager.Singleton == (Object)null)
			{
				return "Unknown";
			}
			if (NetworkManager.Singleton.IsServer && NetworkManager.Singleton.ConnectedClients.TryGetValue(clientId, out var value) && (Object)(object)value.PlayerObject != (Object)null)
			{
				string name = ((Object)value.PlayerObject).name;
				if (!string.IsNullOrEmpty(name) && !IsDefaultPlayerName(name))
				{
					return name;
				}
			}
			PlayerControllerB[] array = Object.FindObjectsByType<PlayerControllerB>((FindObjectsSortMode)0);
			PlayerControllerB[] array2 = array;
			foreach (PlayerControllerB val in array2)
			{
				if (!((Object)(object)val != (Object)null) || val.actualClientId != clientId)
				{
					continue;
				}
				FieldInfo field = typeof(PlayerControllerB).GetField("playerUsername", BindingFlags.Instance | BindingFlags.Public);
				if (field != null)
				{
					string text = field.GetValue(val) as string;
					if (!string.IsNullOrEmpty(text))
					{
						return text;
					}
				}
				if (!string.IsNullOrEmpty(((Object)val).name) && !IsDefaultPlayerName(((Object)val).name))
				{
					return ((Object)val).name;
				}
			}
			return "Unknown";
		}

		private static void SendChatMessage(string message)
		{
			if ((Object)(object)HUDManager.Instance == (Object)null)
			{
				return;
			}
			try
			{
				MethodInfo[] methods = typeof(HUDManager).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				MethodInfo[] array = methods;
				foreach (MethodInfo methodInfo in array)
				{
					string text = methodInfo.Name.ToLower();
					if ((!text.Contains("chat") && !text.Contains("message")) || (!text.Contains("add") && !text.Contains("send")))
					{
						continue;
					}
					try
					{
						ParameterInfo[] parameters = methodInfo.GetParameters();
						if (parameters.Length == 1 && parameters[0].ParameterType == typeof(string))
						{
							methodInfo.Invoke(HUDManager.Instance, new object[1] { message });
							ManualLogSource log = Plugin.Log;
							if (log != null)
							{
								log.LogInfo((object)("[PastaNetwork] 채팅 메시지 전송 성공: " + methodInfo.Name));
							}
							return;
						}
						if (parameters.Length == 2 && parameters[0].ParameterType == typeof(string))
						{
							methodInfo.Invoke(HUDManager.Instance, new object[2] { message, "" });
							ManualLogSource log2 = Plugin.Log;
							if (log2 != null)
							{
								log2.LogInfo((object)("[PastaNetwork] 채팅 메시지 전송 성공: " + methodInfo.Name));
							}
							return;
						}
					}
					catch
					{
					}
				}
				FieldInfo[] fields = typeof(HUDManager).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				FieldInfo[] array2 = fields;
				foreach (FieldInfo fieldInfo in array2)
				{
					string text2 = fieldInfo.Name.ToLower();
					if (!text2.Contains("chat") || (!text2.Contains("text") && !text2.Contains("log")))
					{
						continue;
					}
					try
					{
						object value = fieldInfo.GetValue(HUDManager.Instance);
						if (value == null)
						{
							continue;
						}
						PropertyInfo property = value.GetType().GetProperty("text");
						if (property != null)
						{
							string text3 = (property.GetValue(value) as string) ?? "";
							property.SetValue(value, text3 + "\n" + message);
							ManualLogSource log3 = Plugin.Log;
							if (log3 != null)
							{
								log3.LogInfo((object)("[PastaNetwork] 채팅 메시지 전송 성공 (필드): " + fieldInfo.Name));
							}
							return;
						}
					}
					catch
					{
					}
				}
				ManualLogSource log4 = Plugin.Log;
				if (log4 != null)
				{
					log4.LogWarning((object)"[PastaNetwork] 채팅 메시지 전송 방법을 찾지 못했습니다.");
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log5 = Plugin.Log;
				if (log5 != null)
				{
					log5.LogError((object)$"[PastaNetwork] 채팅 메시지 전송 오류: {arg}");
				}
			}
		}

		private static bool IsDefaultPlayerName(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return true;
			}
			string text = name.ToLower().Trim();
			if (text.StartsWith("player"))
			{
				string text2 = text.Substring(6).Trim();
				if (string.IsNullOrEmpty(text2))
				{
					return true;
				}
				text2 = text2.Replace("#", "").Replace(" ", "");
				if (text2.Length > 0 && Regex.IsMatch(text2, "^\\d+$"))
				{
					return true;
				}
			}
			if (text == "player")
			{
				return true;
			}
			return false;
		}

		private static void OnClientDisconnected(ulong clientId)
		{
			ulong steamID = SteamIDHelper.GetSteamID(clientId);
			_processedConnects.Remove(steamID);
			_processedConnects.Remove(clientId);
			RecentLeaveTracker.Add(clientId);
			if (!((Object)(object)NetworkManager.Singleton != (Object)null))
			{
				return;
			}
			List<ulong> list = new List<ulong>();
			if (NetworkManager.Singleton.IsServer)
			{
				foreach (KeyValuePair<ulong, NetworkClient> connectedClient in NetworkManager.Singleton.ConnectedClients)
				{
					list.Add(connectedClient.Key);
				}
			}
			else
			{
				PlayerControllerB[] array = Object.FindObjectsByType<PlayerControllerB>((FindObjectsSortMode)0);
				PlayerControllerB[] array2 = array;
				foreach (PlayerControllerB val in array2)
				{
					if ((Object)(object)val != (Object)null && val.actualClientId != 0)
					{
						ulong steamID2 = SteamIDHelper.GetSteamID(val.actualClientId);
						if (steamID2 != 0)
						{
							list.Add(steamID2);
						}
					}
				}
			}
			KickTracker.SetCurrentPlayers(list);
			if (!NetworkManager.Singleton.IsServer && clientId == NetworkManager.Singleton.LocalClientId)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)"[PastaNetwork] 킥당한 것으로 감지! UI 표시 중...");
				}
				((MonoBehaviour)Instance).StartCoroutine(ShowKickUIDelayed());
			}
		}

		private static IEnumerator ShowKickUIDelayed()
		{
			yield return (object)new WaitForSeconds(0.5f);
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)"[PastaNetwork] 킥 UI 표시 중...");
			}
			KickUI.ShowKickedBy();
		}

		private static IEnumerator CheckAndKickPlayerDelayed(ulong clientId)
		{
			yield return (object)new WaitForSeconds(1.5f);
			if ((Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsHost)
			{
				yield break;
			}
			ulong steamId = SteamIDHelper.GetSteamID(clientId);
			if (steamId == clientId && clientId < 76561190000000000L)
			{
				yield return (object)new WaitForSeconds(1f);
				steamId = SteamIDHelper.GetSteamID(clientId);
			}
			ServerClient.GetShitterInfo(steamId, delegate(bool success, Dictionary<string, object>? infoData)
			{
				if (success && infoData != null && infoData.ContainsKey("voteCount"))
				{
					int val = (int)infoData["voteCount"];
					if (infoData.ContainsKey("fullJson"))
					{
						string input = infoData["fullJson"].ToString() ?? "";
						string pattern = "\"votes\"\\s*:\\s*\\{([^}]+(?:\\{[^}]+\\}[^}]*)*)\\}";
						Match match = Regex.Match(input, pattern);
						if (match.Success)
						{
							string value = match.Groups[1].Value;
							string pattern2 = "\"(\\d+)\"\\s*:\\s*\\{[^}]*\"reason\"\\s*:\\s*\"([^\"]+)\"";
							MatchCollection matchCollection = Regex.Matches(value, pattern2);
							foreach (Match item in matchCollection)
							{
								if (item.Groups.Count >= 3 && ulong.TryParse(item.Groups[1].Value, out var result))
								{
									string value2 = item.Groups[2].Value;
									value2 = value2.Replace("\\\"", "\"").Replace("\\n", "\n").Replace("\\t", "\t");
									ShitterDatabase.AddVote(steamId, result, value2);
								}
							}
						}
					}
					int voteCount = ShitterDatabase.GetVoteCount(steamId);
					int num = Math.Max(val, voteCount);
					if (ConfigManager.EnableAutoKick.Value && num >= ConfigManager.VoteKickThreshold.Value)
					{
						ManualLogSource log = Plugin.Log;
						if (log != null)
						{
							log.LogInfo((object)$"[PastaNetwork] 자동 킥: Steam ID {steamId}, 투표 {num}개");
						}
						if ((Object)(object)Instance == (Object)null)
						{
							ManualLogSource log2 = Plugin.Log;
							if (log2 != null)
							{
								log2.LogError((object)"[PastaNetwork] Instance is null! Cannot start kick coroutine.");
							}
						}
						else
						{
							((MonoBehaviour)Instance).StartCoroutine(KickPlayerDelayed(clientId, steamId, num));
						}
					}
				}
				else if (ShitterDatabase.IsShitter(steamId))
				{
					int voteCount2 = ShitterDatabase.GetVoteCount(steamId);
					if (ConfigManager.EnableAutoKick.Value && voteCount2 >= ConfigManager.VoteKickThreshold.Value)
					{
						ManualLogSource log3 = Plugin.Log;
						if (log3 != null)
						{
							log3.LogInfo((object)$"[PastaNetwork] 자동 킥 (로컬 DB): Steam ID {steamId}, 투표 {voteCount2}개");
						}
						((MonoBehaviour)Instance).StartCoroutine(KickPlayerDelayed(clientId, steamId, voteCount2));
					}
				}
			});
		}

		private static IEnumerator KickPlayerDelayed(ulong clientId, ulong steamId, int votes)
		{
			yield return (object)new WaitForSeconds(1f);
			if ((Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsHost)
			{
				yield break;
			}
			ulong actualClientId = clientId;
			if (clientId > 76561190000000000L && clientId < 76561199999999999L)
			{
				actualClientId = SteamIDHelper.GetClientID(steamId);
				if (actualClientId == steamId || actualClientId == clientId)
				{
					foreach (KeyValuePair<ulong, NetworkClient> connectedClient in NetworkManager.Singleton.ConnectedClients)
					{
						ulong connectedClientId = connectedClient.Key;
						ulong connectedSteamId = SteamIDHelper.GetSteamID(connectedClientId);
						if (connectedSteamId == steamId)
						{
							actualClientId = connectedClientId;
							break;
						}
					}
				}
			}
			if (!NetworkManager.Singleton.ConnectedClients.ContainsKey(actualClientId))
			{
				yield break;
			}
			try
			{
				ShitterInfo shitterInfo = ShitterDatabase.Get(steamId);
				string playerName = SteamNameFetcher.GetCachedName(steamId);
				if (playerName == "Unknown")
				{
					playerName = GetPlayerName(actualClientId);
					if (playerName == "Unknown")
					{
						playerName = $"플레이어 ({steamId})";
					}
				}
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)"═══════════════════════════════════════════════════════");
				}
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogInfo((object)$"\ud83d\udeab 자동 킥 실행: {playerName} (Steam ID: {steamId})");
				}
				ManualLogSource log3 = Plugin.Log;
				if (log3 != null)
				{
					log3.LogInfo((object)$"\ud83d\udcca 총 투표 수: {votes}개 (임계값: {ConfigManager.VoteKickThreshold.Value}개)");
				}
				if (shitterInfo != null && shitterInfo.Reasons.Count > 0)
				{
					ManualLogSource log4 = Plugin.Log;
					if (log4 != null)
					{
						log4.LogInfo((object)"───────────────────────────────────────────────────────");
					}
					ManualLogSource log5 = Plugin.Log;
					if (log5 != null)
					{
						log5.LogInfo((object)"\ud83d\udcdd 투표 사유:");
					}
					int index = 1;
					foreach (KeyValuePair<ulong, string> kvp in shitterInfo.Reasons)
					{
						ulong voterSteamId = kvp.Key;
						string reason = kvp.Value;
						string voterName = SteamNameFetcher.GetCachedName(voterSteamId);
						if (voterName == "Unknown")
						{
							voterName = $"플레이어 ({voterSteamId})";
						}
						ManualLogSource log6 = Plugin.Log;
						if (log6 != null)
						{
							log6.LogInfo((object)$"  {index}. [{voterName}] {reason}");
						}
						index++;
					}
				}
				else
				{
					ManualLogSource log7 = Plugin.Log;
					if (log7 != null)
					{
						log7.LogInfo((object)"───────────────────────────────────────────────────────");
					}
					ManualLogSource log8 = Plugin.Log;
					if (log8 != null)
					{
						log8.LogInfo((object)"⚠\ufe0f 투표 사유 정보를 가져올 수 없습니다. (로컬 DB에 없음)");
					}
				}
				ManualLogSource log9 = Plugin.Log;
				if (log9 != null)
				{
					log9.LogInfo((object)"═══════════════════════════════════════════════════════");
				}
				NetworkManager.Singleton.DisconnectClient(actualClientId);
				_processedConnects.Remove(steamId);
				_processedConnects.Remove(actualClientId);
				if ((Object)(object)HUDManager.Instance != (Object)null)
				{
					HUDManager.Instance.DisplayTip("Pasta Client", $"자동킥됨 (Shitter, 투표: {votes})", false, false, "LC_Tip1");
					SendChatMessage($"{playerName}이(가) Shitter 투표 {votes}개로 인해 자동 킥되었습니다.");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log10 = Plugin.Log;
				if (log10 != null)
				{
					log10.LogError((object)$"[PastaNetwork] 킥 실행 중 오류: {ex}");
				}
			}
		}

		[ServerRpc(RequireOwnership = false)]
		public void AddShitterServerRpc(ulong targetId, string reason, ulong senderId)
		{
			ShitterDatabase.AddVote(targetId, senderId, reason);
			UpdateShitterClientsClientRpc(targetId);
			if (!((NetworkBehaviour)this).IsHost || !((Object)(object)NetworkManager.Singleton != (Object)null))
			{
				return;
			}
			int voteCount = ShitterDatabase.GetVoteCount(targetId);
			if (!ConfigManager.EnableAutoKick.Value || voteCount < ConfigManager.VoteKickThreshold.Value)
			{
				return;
			}
			ulong clientID = SteamIDHelper.GetClientID(targetId);
			if (NetworkManager.Singleton.ConnectedClients.ContainsKey(clientID))
			{
				((MonoBehaviour)Instance).StartCoroutine(KickPlayerDelayed(clientID, targetId, voteCount));
				return;
			}
			foreach (KeyValuePair<ulong, NetworkClient> connectedClient in NetworkManager.Singleton.ConnectedClients)
			{
				ulong key = connectedClient.Key;
				ulong steamID = SteamIDHelper.GetSteamID(key);
				if (steamID == targetId)
				{
					((MonoBehaviour)Instance).StartCoroutine(KickPlayerDelayed(key, targetId, voteCount));
					break;
				}
			}
		}

		[ClientRpc]
		public void UpdateShitterClientsClientRpc(ulong id)
		{
			Plugin.Log.LogDebug((object)$"[PastaNetwork] UpdateShitterClientsClientRpc: {id}");
			ShitterUI.OnDatabaseUpdated(id);
		}

		[ClientRpc]
		public void SendPlayerListClientRpc(ulong[] playerIds, ClientRpcParams rpcParams = default(ClientRpcParams))
		{
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)$"[PastaNetwork] 방 플레이어 목록 수신: {playerIds.Length}명");
			}
			KickTracker.SetCurrentPlayers(playerIds);
			foreach (ulong num in playerIds)
			{
				if (num != 0)
				{
					((MonoBehaviour)Instance).StartCoroutine(CachePlayerNameDelayed(num));
				}
			}
		}

		public static void RequestAddShitter(ulong targetId, string reason)
		{
			string reason2 = reason;
			if ((Object)(object)Instance == (Object)null)
			{
				return;
			}
			ulong targetSteamId = SteamIDHelper.GetSteamID(targetId);
			ulong senderSteamId = 0uL;
			if ((Object)(object)NetworkManager.Singleton != (Object)null)
			{
				senderSteamId = SteamIDHelper.GetSteamID(NetworkManager.Singleton.LocalClientId);
			}
			ServerClient.SendShitterVote(targetSteamId, senderSteamId, reason2, delegate(bool success, string response)
			{
				if (success)
				{
					try
					{
						if (response.Contains("\"voteCount\""))
						{
							Match match = Regex.Match(response, "\"voteCount\"\\s*:\\s*(\\d+)");
							if (match.Success && int.TryParse(match.Groups[1].Value, out var result) && (Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsServer && NetworkManager.Singleton.IsHost && ConfigManager.EnableAutoKick.Value && result >= ConfigManager.VoteKickThreshold.Value)
							{
								ulong clientID = SteamIDHelper.GetClientID(targetSteamId);
								if (NetworkManager.Singleton.ConnectedClients.ContainsKey(clientID))
								{
									((MonoBehaviour)Instance).StartCoroutine(KickPlayerDelayed(clientID, targetSteamId, result));
								}
							}
						}
					}
					catch (Exception ex)
					{
						ManualLogSource log = Plugin.Log;
						if (log != null)
						{
							log.LogWarning((object)("[PastaNetwork] 서버 응답 파싱 오류: " + ex.Message));
						}
					}
					HUDManager instance = HUDManager.Instance;
					if (instance != null)
					{
						instance.DisplayTip("Pasta Client", "Shitter 추가 요청 전송됨", false, false, "LC_Tip1");
					}
					ShitterDatabase.AddVote(targetSteamId, senderSteamId, reason2);
					ShitterUI.OnDatabaseUpdated(targetSteamId);
					if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsServer && (Object)(object)Instance != (Object)null)
					{
						try
						{
							ulong localClientId = NetworkManager.Singleton.LocalClientId;
							Instance.AddShitterServerRpc(targetSteamId, reason2, senderSteamId);
						}
						catch (Exception ex2)
						{
							ManualLogSource log2 = Plugin.Log;
							if (log2 != null)
							{
								log2.LogWarning((object)("[PastaNetwork] Failed to call AddShitterServerRpc: " + ex2.Message));
							}
						}
					}
				}
				else
				{
					ManualLogSource log3 = Plugin.Log;
					if (log3 != null)
					{
						log3.LogError((object)("[PastaNetwork] Failed to send shitter vote to server: " + response));
					}
					HUDManager instance2 = HUDManager.Instance;
					if (instance2 != null)
					{
						instance2.DisplayTip("Pasta Client", "서버 요청 실패", false, false, "LC_Tip1");
					}
				}
			});
		}
	}
	[BepInPlugin("dev523.pasta.client", "Pasta Client", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public static ManualLogSource Log;

		private void Awake()
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)"Pasta Client Loaded!");
			ConfigManager.Init(((BaseUnityPlugin)this).Config);
			Harmony val = new Harmony("dev523.pasta.client");
			val.PatchAll();
			PastaNetwork.Init();
			ShitterDatabase.Init();
			RecentLeaveTracker.Init((MonoBehaviour?)(object)PastaNetwork.Instance);
			KickTracker.Init();
			ChatCommandHandler.Init();
			Object.DontDestroyOnLoad((Object)(object)this);
		}
	}
	public static class KickTracker
	{
		public static List<ulong> LastPlayersInRoom = new List<ulong>();

		public static void Init()
		{
		}

		public static void SetCurrentPlayers(IEnumerable<ulong> ids)
		{
			LastPlayersInRoom = new List<ulong>(ids);
		}
	}
	public class RecentPlayerInfo
	{
		public ulong ClientId;

		public string PlayerName;

		public bool IsNameLoading;

		public RecentPlayerInfo(ulong clientId, string playerName, bool isNameLoading = false)
		{
			ClientId = clientId;
			PlayerName = playerName ?? "Unknown";
			IsNameLoading = isNameLoading;
		}
	}
	public static class RecentLeaveTracker
	{
		private static readonly LinkedList<RecentPlayerInfo> _recent = new LinkedList<RecentPlayerInfo>();

		private static readonly Dictionary<ulong, string> _playerNameCache = new Dictionary<ulong, string>();

		private const int Max = 10;

		private static MonoBehaviour? _coroutineRunner;

		public static void Init(MonoBehaviour? coroutineRunner = null)
		{
			_coroutineRunner = coroutineRunner;
		}

		public static void Add(ulong clientId)
		{
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)"[RecentLeaveTracker] ========================================");
			}
			ManualLogSource log2 = Plugin.Log;
			if (log2 != null)
			{
				log2.LogInfo((object)"[RecentLeaveTracker] 나간 플레이어 리스트에 추가 중...");
			}
			ManualLogSource log3 = Plugin.Log;
			if (log3 != null)
			{
				log3.LogInfo((object)$"[RecentLeaveTracker] Steam ID: {clientId}");
			}
			string value;
			string text = (_playerNameCache.TryGetValue(clientId, out value) ? value : "Unknown");
			ManualLogSource log4 = Plugin.Log;
			if (log4 != null)
			{
				log4.LogInfo((object)("[RecentLeaveTracker] 캐시에서 가져온 이름: " + text));
			}
			if (text == "Unknown")
			{
				text = GetPlayerNameFromGame(clientId);
				ManualLogSource log5 = Plugin.Log;
				if (log5 != null)
				{
					log5.LogInfo((object)("[RecentLeaveTracker] 게임에서 가져온 이름: " + text));
				}
				if (text != "Unknown" && !string.IsNullOrEmpty(text))
				{
					_playerNameCache[clientId] = text;
				}
			}
			bool flag = text == "Unknown";
			ManualLogSource log6 = Plugin.Log;
			if (log6 != null)
			{
				log6.LogInfo((object)("[RecentLeaveTracker] 현재 플레이어 이름: " + text));
			}
			ManualLogSource log7 = Plugin.Log;
			if (log7 != null)
			{
				log7.LogInfo((object)$"[RecentLeaveTracker] 이름 로딩 중: {flag}");
			}
			RecentPlayerInfo value2 = new RecentPlayerInfo(clientId, text, flag);
			_recent.AddFirst(value2);
			while (_recent.Count > 10)
			{
				_recent.RemoveLast();
			}
			ManualLogSource log8 = Plugin.Log;
			if (log8 != null)
			{
				log8.LogInfo((object)$"[RecentLeaveTracker] 리스트에 추가 완료! (총 {_recent.Count}명)");
			}
			if (flag && (Object)(object)_coroutineRunner != (Object)null)
			{
				ManualLogSource log9 = Plugin.Log;
				if (log9 != null)
				{
					log9.LogInfo((object)"[RecentLeaveTracker] Steam API로 이름 가져오기 시작...");
				}
				SteamNameFetcher.FetchPlayerNameFromGameOrSteam(clientId, delegate(ulong steamId, string name)
				{
					ManualLogSource log15 = Plugin.Log;
					if (log15 != null)
					{
						log15.LogInfo((object)"[RecentLeaveTracker] ========================================");
					}
					ManualLogSource log16 = Plugin.Log;
					if (log16 != null)
					{
						log16.LogInfo((object)"[RecentLeaveTracker] Steam API 이름 가져오기 완료!");
					}
					ManualLogSource log17 = Plugin.Log;
					if (log17 != null)
					{
						log17.LogInfo((object)$"[RecentLeaveTracker] Steam ID: {steamId}");
					}
					ManualLogSource log18 = Plugin.Log;
					if (log18 != null)
					{
						log18.LogInfo((object)("[RecentLeaveTracker] 플레이어 이름: " + name));
					}
					ManualLogSource log19 = Plugin.Log;
					if (log19 != null)
					{
						log19.LogInfo((object)"[RecentLeaveTracker] ========================================");
					}
					UpdatePlayerName(steamId, name);
				});
			}
			else if (!flag)
			{
				ManualLogSource log10 = Plugin.Log;
				if (log10 != null)
				{
					log10.LogInfo((object)"[RecentLeaveTracker] ========================================");
				}
				ManualLogSource log11 = Plugin.Log;
				if (log11 != null)
				{
					log11.LogInfo((object)"[RecentLeaveTracker] 나간 플레이어 정보:");
				}
				ManualLogSource log12 = Plugin.Log;
				if (log12 != null)
				{
					log12.LogInfo((object)$"[RecentLeaveTracker] Steam ID: {clientId}");
				}
				ManualLogSource log13 = Plugin.Log;
				if (log13 != null)
				{
					log13.LogInfo((object)("[RecentLeaveTracker] 플레이어 이름: " + text));
				}
				ManualLogSource log14 = Plugin.Log;
				if (log14 != null)
				{
					log14.LogInfo((object)"[RecentLeaveTracker] ========================================");
				}
			}
		}

		public static void CachePlayerName(ulong clientId, string playerName)
		{
			if (!string.IsNullOrEmpty(playerName) && playerName != "Unknown")
			{
				_playerNameCache[clientId] = playerName;
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)$"[RecentLeaveTracker] Cached player name: {clientId} = {playerName}");
				}
			}
			if (!((Object)(object)_coroutineRunner != (Object)null))
			{
				return;
			}
			SteamNameFetcher.FetchPlayerNameFromGameOrSteam(clientId, delegate(ulong steamId, string name)
			{
				if (!string.IsNullOrEmpty(name) && name != "Unknown")
				{
					_playerNameCache[steamId] = name;
					ManualLogSource log2 = Plugin.Log;
					if (log2 != null)
					{
						log2.LogInfo((object)$"[RecentLeaveTracker] Updated cached name from Steam: {steamId} = {name}");
					}
				}
			});
		}

		private static void UpdatePlayerName(ulong clientId, string playerName)
		{
			foreach (RecentPlayerInfo item in _recent)
			{
				if (item.ClientId == clientId)
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogInfo((object)$"[RecentLeaveTracker] 리스트에서 이름 업데이트: Steam ID {clientId}, 이전 이름: {item.PlayerName} -> 새 이름: {playerName}");
					}
					item.PlayerName = playerName;
					item.IsNameLoading = false;
					if (!string.IsNullOrEmpty(playerName) && playerName != "Unknown")
					{
						_playerNameCache[clientId] = playerName;
					}
					break;
				}
			}
		}

		private static string GetPlayerNameFromGame(ulong clientId)
		{
			if ((Object)(object)NetworkManager.Singleton == (Object)null)
			{
				return "Unknown";
			}
			if (NetworkManager.Singleton.IsServer && NetworkManager.Singleton.ConnectedClients.TryGetValue(clientId, out var value) && (Object)(object)value.PlayerObject != (Object)null)
			{
				string name = ((Object)value.PlayerObject).name;
				if (!string.IsNullOrEmpty(name) && name != "Player")
				{
					return name;
				}
			}
			PlayerControllerB[] array = Object.FindObjectsByType<PlayerControllerB>((FindObjectsSortMode)0);
			PlayerControllerB[] array2 = array;
			foreach (PlayerControllerB val in array2)
			{
				if (!((Object)(object)val != (Object)null) || val.actualClientId != clientId)
				{
					continue;
				}
				FieldInfo field = typeof(PlayerControllerB).GetField("playerUsername", BindingFlags.Instance | BindingFlags.Public);
				if (field != null)
				{
					string text = field.GetValue(val) as string;
					if (!string.IsNullOrEmpty(text))
					{
						return text;
					}
				}
				if (!string.IsNullOrEmpty(((Object)val).name) && ((Object)val).name != "Player")
				{
					return ((Object)val).name;
				}
			}
			return "Unknown";
		}

		public static IEnumerable<RecentPlayerInfo> GetAll()
		{
			return _recent;
		}

		public static IEnumerable<ulong> GetAllIds()
		{
			return _recent.Select((RecentPlayerInfo p) => p.ClientId);
		}
	}
	public class ShitterInfo
	{
		public ulong SteamId;

		public Dictionary<ulong, string> Reasons = new Dictionary<ulong, string>();

		public ShitterInfo(ulong id)
		{
			SteamId = id;
		}
	}
	public static class ShitterDatabase
	{
		private static readonly Dictionary<ulong, ShitterInfo> _shitters = new Dictionary<ulong, ShitterInfo>();

		public static void Init()
		{
		}

		public static void AddVote(ulong targetId, ulong voterId, string reason)
		{
			if (targetId != voterId)
			{
				if (!_shitters.TryGetValue(targetId, out ShitterInfo value))
				{
					value = new ShitterInfo(targetId);
					_shitters[targetId] = value;
				}
				if (!value.Reasons.ContainsKey(voterId))
				{
					value.Reasons[voterId] = reason;
				}
			}
		}

		public static bool IsShitter(ulong id)
		{
			return _shitters.ContainsKey(id);
		}

		public static int GetVoteCount(ulong id)
		{
			ShitterInfo value;
			return _shitters.TryGetValue(id, out value) ? value.Reasons.Count : 0;
		}

		public static IEnumerable<ShitterInfo> All()
		{
			return _shitters.Values;
		}

		public static ShitterInfo? Get(ulong id)
		{
			ShitterInfo value;
			return _shitters.TryGetValue(id, out value) ? value : null;
		}
	}
	public static class KickUI
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static Action <0>__OnGUI;

			public static WindowFunction <1>__WindowFunc;
		}

		private static bool _open;

		private static Rect _rect = new Rect(140f, 140f, 400f, 400f);

		public static void ShowKickedBy()
		{
			if (ConfigManager.EnableShitterUIOnKick.Value)
			{
				_open = true;
				UIHelper.Register(OnGUI);
			}
		}

		private static void Close()
		{
			_open = false;
			UIHelper.Unregister(OnGUI);
		}

		private static void OnGUI()
		{
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Expected O, but got Unknown
			if (!_open)
			{
				return;
			}
			try
			{
				if (((Rect)(ref _rect)).x == 140f && ((Rect)(ref _rect)).y == 140f)
				{
					((Rect)(ref _rect)).x = ((float)Screen.width - ((Rect)(ref _rect)).width) / 2f;
					((Rect)(ref _rect)).y = ((float)Screen.height - ((Rect)(ref _rect)).height) / 2f;
				}
				Rect rect = _rect;
				object obj = <>O.<1>__WindowFunc;
				if (obj == null)
				{
					WindowFunction val = WindowFunc;
					<>O.<1>__WindowFunc = val;
					obj = (object)val;
				}
				_rect = GUILayout.Window(987656, rect, (WindowFunction)obj, "킥당함 - 방 목록", UIStyle.WindowStyle, Array.Empty<GUILayoutOption>());
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[KickUI] Error in OnGUI: {arg}");
				}
			}
		}

		private static void WindowFunc(int id)
		{
			//IL_007f: 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_022b: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
			GUILayout.Label("킥 당했을 때 방에 있던 플레이어 목록입니다.", UIStyle.LabelStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Box("", UIStyle.BoxStyle, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Height(1f),
				GUILayout.ExpandWidth(true)
			});
			GUILayout.Space(10f);
			List<ulong> lastPlayersInRoom = KickTracker.LastPlayersInRoom;
			if (lastPlayersInRoom != null && lastPlayersInRoom.Count > 0)
			{
				GUILayout.BeginScrollView(Vector2.zero, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandHeight(true) });
				foreach (ulong item in lastPlayersInRoom)
				{
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					GUILayout.Label($"[{item}]", UIStyle.LabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) });
					if (GUILayout.Button("Steam 프로필", UIStyle.ButtonStyle, Array.Empty<GUILayoutOption>()))
					{
						ulong steamID = SteamIDHelper.GetSteamID(item);
						ManualLogSource log = Plugin.Log;
						if (log != null)
						{
							log.LogInfo((object)$"[KickUI] Opening Steam profile: clientId={item}, steamId={steamID}");
						}
						Application.OpenURL($"https://steamcommunity.com/profiles/{steamID}");
					}
					GUILayout.EndHorizontal();
					GUILayout.Space(5f);
				}
				GUILayout.EndScrollView();
			}
			else
			{
				GUILayout.Label("목록이 비어있습니다.", UIStyle.LabelStyle, Array.Empty<GUILayoutOption>());
			}
			GUILayout.Space(10f);
			GUILayout.Box("", UIStyle.BoxStyle, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Height(1f),
				GUILayout.ExpandWidth(true)
			});
			GUILayout.Space(5f);
			if (GUILayout.Button("닫기", UIStyle.ButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
			{
				Close();
			}
			GUILayout.EndVertical();
			GUI.DragWindow(new Rect(0f, 0f, ((Rect)(ref _rect)).width, 20f));
		}
	}
	public static class RecentUI
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static Action <0>__OnGUI;

			public static WindowFunction <1>__WindowFunc;
		}

		private static bool _open;

		private static Rect _rect = new Rect(120f, 120f, 450f, 500f);

		public static void Open()
		{
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)"[RecentUI] Open() called");
			}
			_open = true;
			UIHelper.Register(OnGUI);
			ManualLogSource log2 = Plugin.Log;
			if (log2 != null)
			{
				log2.LogInfo((object)$"[RecentUI] UI registered, _open = {_open}");
			}
		}

		public static void Close()
		{
			_open = false;
			UIHelper.Unregister(OnGUI);
		}

		private static void OnGUI()
		{
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Expected O, but got Unknown
			if (!_open)
			{
				return;
			}
			try
			{
				if (((Rect)(ref _rect)).x == 120f && ((Rect)(ref _rect)).y == 120f)
				{
					((Rect)(ref _rect)).x = ((float)Screen.width - ((Rect)(ref _rect)).width) / 2f;
					((Rect)(ref _rect)).y = ((float)Screen.height - ((Rect)(ref _rect)).height) / 2f;
				}
				Rect rect = _rect;
				object obj = <>O.<1>__WindowFunc;
				if (obj == null)
				{
					WindowFunction val = WindowFunc;
					<>O.<1>__WindowFunc = val;
					obj = (object)val;
				}
				_rect = GUILayout.Window(987655, rect, (WindowFunction)obj, "최근 나간 사람들", UIStyle.WindowStyle, Array.Empty<GUILayoutOption>());
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[RecentUI] Error in OnGUI: {arg}");
				}
			}
		}

		private static void WindowFunc(int id)
		{
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
			GUILayout.Label("최근에 방을 나간 플레이어 목록입니다.", UIStyle.LabelStyle, Array.Empty<GUILayoutOption>());
			GUILayout.Box("", UIStyle.BoxStyle, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Height(1f),
				GUILayout.ExpandWidth(true)
			});
			GUILayout.Space(10f);
			List<RecentPlayerInfo> list = RecentLeaveTracker.GetAll().ToList();
			if (list.Count > 0)
			{
				GUILayout.BeginScrollView(Vector2.zero, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandHeight(true) });
				foreach (RecentPlayerInfo item in list)
				{
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					string arg = (item.IsNameLoading ? "Loading..." : item.PlayerName);
					GUILayout.Label($"[{item.ClientId}] {arg}", UIStyle.LabelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(250f) });
					if (GUILayout.Button("Steam 프로필", UIStyle.ButtonStyle, Array.Empty<GUILayoutOption>()))
					{
						ulong steamID = SteamIDHelper.GetSteamID(item.ClientId);
						ManualLogSource log = Plugin.Log;
						if (log != null)
						{
							log.LogInfo((object)$"[RecentUI] Opening Steam profile: clientId={item.ClientId}, steamId={steamID}");
						}
						Application.OpenURL($"https://steamcommunity.com/profiles/{steamID}");
					}
					GUILayout.EndHorizontal();
					GUILayout.Space(5f);
				}
				GUILayout.EndScrollView();
			}
			else
			{
				GUILayout.Label("목록이 비어있습니다.", UIStyle.LabelStyle, Array.Empty<GUILayoutOption>());
			}
			GUILayout.Space(10f);
			GUILayout.Box("", UIStyle.BoxStyle, (GUILayoutOption[])(object)new GUILayoutOption[2]
			{
				GUILayout.Height(1f),
				GUILayout.ExpandWidth(true)
			});
			GUILayout.Space(5f);
			if (GUILayout.Button("닫기", UIStyle.ButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
			{
				Close();
			}
			GUILayout.EndVertical();
			GUI.DragWindow(new Rect(0f, 0f, ((Rect)(ref _rect)).width, 20f));
		}
	}
	[Serializable]
	public class ShitterVoteRequest
	{
		public string targetId = "";

		public string senderId = "";

		public string reason = "";

		public long timestamp;
	}
	public static class ServerClient
	{
		private static MonoBehaviour? _coroutineRunner;

		private const string DEFAULT_SERVER_URL = "https://shitter.asta.rs";

		public static void Init(MonoBehaviour coroutineRunner)
		{
			_coroutineRunner = coroutineRunner;
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)"[ServerClient] Initialized");
			}
		}

		public static void SendShitterVote(ulong targetId, ulong senderId, string reason, Action<bool, string>? onComplete = null)
		{
			if ((Object)(object)_coroutineRunner == (Object)null)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)"[ServerClient] CoroutineRunner not initialized!");
				}
				onComplete?.Invoke(arg1: false, "CoroutineRunner not initialized");
				return;
			}
			string text = ConfigManager.ServerUrl?.Value ?? "https://shitter.asta.rs";
			string url = text + "/api/shitter/vote";
			ManualLogSource log2 = Plugin.Log;
			if (log2 != null)
			{
				log2.LogInfo((object)$"[ServerClient] Sending shitter vote: targetId={targetId}, senderId={senderId}, reason={reason}");
			}
			_coroutineRunner.StartCoroutine(SendVoteCoroutine(url, targetId, senderId, reason, onComplete));
		}

		private static IEnumerator SendVoteCoroutine(string url, ulong targetId, ulong senderId, string reason, Action<bool, string>? onComplete)
		{
			ShitterVoteRequest jsonData = new ShitterVoteRequest
			{
				targetId = targetId.ToString(),
				senderId = senderId.ToString(),
				reason = reason,
				timestamp = (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds
			};
			string json = JsonUtility.ToJson((object)jsonData);
			byte[] bodyRaw = Encoding.UTF8.GetBytes(json);
			UnityWebRequest request = new UnityWebRequest(url, "POST");
			try
			{
				request.uploadHandler = (UploadHandler)new UploadHandlerRaw(bodyRaw);
				request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
				request.SetRequestHeader("Content-Type", "application/json");
				request.SetRequestHeader("User-Agent", "PastaClient/1.0");
				yield return request.SendWebRequest();
				if ((int)request.result == 1)
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogInfo((object)("[ServerClient] Vote sent successfully: " + request.downloadHandler.text));
					}
					onComplete?.Invoke(arg1: true, request.downloadHandler.text);
				}
				else
				{
					ManualLogSource log2 = Plugin.Log;
					if (log2 != null)
					{
						log2.LogError((object)("[ServerClient] Failed to send vote: " + request.error));
					}
					onComplete?.Invoke(arg1: false, request.error ?? "Unknown error");
				}
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		public static void GetShitterInfo(ulong targetId, Action<bool, Dictionary<string, object>?>? onComplete = null)
		{
			if ((Object)(object)_coroutineRunner == (Object)null)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)"[ServerClient] CoroutineRunner not initialized!");
				}
				onComplete?.Invoke(arg1: false, null);
				return;
			}
			string arg = ConfigManager.ServerUrl?.Value ?? "https://shitter.asta.rs";
			string url = $"{arg}/api/shitter/info/{targetId}";
			ManualLogSource log2 = Plugin.Log;
			if (log2 != null)
			{
				log2.LogInfo((object)$"[ServerClient] Getting shitter info: targetId={targetId}");
			}
			_coroutineRunner.StartCoroutine(GetInfoCoroutine(url, onComplete));
		}

		private static IEnumerator GetInfoCoroutine(string url, Action<bool, Dictionary<string, object>?>? onComplete)
		{
			UnityWebRequest request = UnityWebRequest.Get(url);
			try
			{
				request.SetRequestHeader("User-Agent", "PastaClient/1.0");
				yield return request.SendWebRequest();
				if ((int)request.result == 1)
				{
					try
					{
						string json = request.downloadHandler.text;
						Dictionary<string, object> result = new Dictionary<string, object>();
						Match voteCountMatch = Regex.Match(json, "\"voteCount\"\\s*:\\s*(\\d+)");
						if (voteCountMatch.Success && int.TryParse(voteCountMatch.Groups[1].Value, out var voteCount))
						{
							result["voteCount"] = voteCount;
						}
						else
						{
							result["voteCount"] = 0;
						}
						Match steamIdMatch = Regex.Match(json, "\"steamId\"\\s*:\\s*\"?(\\d+)\"?");
						if (steamIdMatch.Success && ulong.TryParse(steamIdMatch.Groups[1].Value, out var steamId))
						{
							result["steamId"] = steamId;
						}
						if (json.Contains("\"votes\""))
						{
							result["hasVotes"] = true;
							result["fullJson"] = json;
						}
						onComplete?.Invoke(arg1: true, result);
					}
					catch (Exception ex2)
					{
						Exception ex = ex2;
						ManualLogSource log = Plugin.Log;
						if (log != null)
						{
							log.LogError((object)$"[ServerClient] Error parsing response: {ex}");
						}
						onComplete?.Invoke(arg1: false, null);
					}
				}
				else
				{
					ManualLogSource log2 = Plugin.Log;
					if (log2 != null)
					{
						log2.LogError((object)("[ServerClient] Failed to get info: " + request.error));
					}
					onComplete?.Invoke(arg1: false, null);
				}
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}
	}
	public static class ShitterUI
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static Action <0>__OnGUI;

			public static WindowFunction <1>__WindowFunc;
		}

		private static bool _open = false;

		private static Rect _windowRect = new Rect(100f, 100f, 500f, 550f);

		private static Vector2 _scroll = Vector2.zero;

		private static ulong _selectedId = 0uL;

		private static string _reason = "";

		private const string REASON_TEXTAREA_ID = "ShitterReasonTextArea";

		public static void Open()
		{
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)"[ShitterUI] Open() called");
			}
			_open = true;
			UIHelper.Register(OnGUI);
			ManualLogSource log2 = Plugin.Log;
			if (log2 != null)
			{
				log2.LogInfo((object)$"[ShitterUI] UI registered, _open = {_open}");
			}
		}

		public static void Close()
		{
			_open = false;
			UIHelper.Unregister(OnGUI);
		}

		public static void OnDatabaseUpdated(ulong id)
		{
		}

		private static void OnGUI()
		{
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Expected O, but got Unknown
			if (!_open)
			{
				return;
			}
			try
			{
				if (((Rect)(ref _windowRect)).x == 100f && ((Rect)(ref _windowRect)).y == 100f)
				{
					((Rect)(ref _windowRect)).x = ((float)Screen.width - ((Rect)(ref _windowRect)).width) / 2f;
					((Rect)(ref _windowRect)).y = ((float)Screen.height - ((Rect)(ref _windowRect)).height) / 2f;
				}
				Rect windowRect = _windowRect;
				object obj = <>O.<1>__WindowFunc;
				if (obj == null)
				{
					WindowFunction val = WindowFunc;
					<>O.<1>__WindowFunc = val;
					obj = (object)val;
				}
				_windowRect = GUILayout.Window(987654, windowRect, (WindowFunction)obj, "Shitter 추가/확인", UIStyle.WindowStyle, Array.Empty<GUILayoutOption>());
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"[ShitterUI] Error in OnGUI: {arg}");
				}
			}
		}

		private static void WindowFunc(int id)
		{
			//IL_0600: 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_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
			try
			{
				GUILayout.Label("현재 방 플레이어:", UIStyle.LabelStyle, Array.Empty<GUILayoutOption>());
				GUILayout.Box("", UIStyle.BoxStyle, (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.Height(1f),
					GUILayout.ExpandWidth(true)
				});
				_scroll = GUILayout.BeginScrollView(_scroll, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(120f) });
				try
				{
					Dictionary<ulong, string> dictionary = new Dictionary<ulong, string>();
					PlayerControllerB[] array = Object.FindObjectsByType<PlayerControllerB>((FindObjectsSortMode)0);
					if (array != null && array.Length != 0)
					{
						PlayerControllerB[] array2 = array;
						foreach (PlayerControllerB val in array2)
						{
							if ((Object)(object)val != (Object)null && val.actualClientId != 0)
							{
								ulong actualClientId = val.actualClientId;
								ulong steamIDFromPlayer = GetSteamIDFromPlayer(val, actualClientId);
								string text = GetPlayerNameForUI(val, steamIDFromPlayer);
								if (IsDefaultPlayerName(text))
								{
									text = "Unknown";
								}
								if (!dictionary.ContainsKey(steamIDFromPlayer))
								{
									dictionary[steamIDFromPlayer] = text;
								}
							}
						}
					}
					foreach (ulong item in KickTracker.LastPlayersInRoom)
					{
						if (item != 0L && !dictionary.ContainsKey(item))
						{
							string text2 = SteamNameFetcher.GetCachedName(item);
							if (text2 == "Unknown")
							{
								SteamNameFetcher.FetchPlayerNameFromGameOrSteam(item, delegate
								{
								});
								text2 = "Loading...";
							}
							if (IsDefaultPlayerName(text2))
							{
								text2 = "Loading...";
							}
							dictionary[item] = text2;
						}
					}
					if (dictionary.Count > 0)
					{
						foreach (KeyValuePair<ulong, string> item2 in dictionary)
						{
							string text3 = $"[{item2.Key}] {item2.Value}";
							if (GUILayout.Button(text3, UIStyle.ButtonStyle, Array.Empty<GUILayoutOption>()))
							{
								_selectedId = item2.Key;
							}
						}
					}
					else
					{
						GUILayout.Label("플레이어 없음", UIStyle.LabelStyle, Array.Empty<GUILayoutOption>());
					}
				}
				catch (Exception arg)
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogError((object)$"[ShitterUI] Error getting players: {arg}");
					}
					GUILayout.Label("오류 발생", UIStyle.LabelStyle, Array.Empty<GUILayoutOption>());
				}
				finally
				{
					GUILayout.EndScrollView();
				}
				GUILayout.Space(10f);
				GUILayout.Label("최근 나간 플레이어:", UIStyle.LabelStyle, Array.Empty<GUILayoutOption>());
				GUILayout.Box("", UIStyle.BoxStyle, (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.Height(1f),
					GUILayout.ExpandWidth(true)
				});
				List<RecentPlayerInfo> list = RecentLeaveTracker.GetAll().ToList();
				if (list.Count > 0)
				{
					foreach (RecentPlayerInfo item3 in list)
					{
						string text4 = $"[{item3.ClientId}] {item3.PlayerName}";
						if (GUILayout.Button(text4, UIStyle.ButtonStyle, Array.Empty<GUILayoutOption>()))
						{
							_selectedId = item3.ClientId;
						}
					}
				}
				else
				{
					GUILayout.Label("없음", UIStyle.LabelStyle, Array.Empty<GUILayoutOption>());
				}
				GUILayout.Space(10f);
				GUILayout.Box("", UIStyle.BoxStyle, (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.Height(1f),
					GUILayout.ExpandWidth(true)
				});
				GUILayout.Space(5f);
				if (_selectedId != 0)
				{
					GUILayout.Label($"선택된 플레이어: {_selectedId}", UIStyle.LabelStyle, Array.Empty<GUILayoutOption>());
				}
				else
				{
					GUILayout.Label("플레이어를 선택하세요", UIStyle.LabelStyle, Array.Empty<GUILayoutOption>());
				}
				GUILayout.Space(5f);
				GUILayout.Label("이유 입력:", UIStyle.LabelStyle, Array.Empty<GUILayoutOption>());
				GUI.SetNextControlName("ShitterReasonTextArea");
				_reason = GUILayout.TextArea(_reason, 500, UIStyle.TextFieldStyle, (GUILayoutOption[])(object)new GUILayoutOption[2]
				{
					GUILayout.Height(120f),
					GUILayout.ExpandWidth(true)
				});
				string nameOfFocusedControl = GUI.GetNameOfFocusedControl();
				if (nameOfFocusedControl == "ShitterReasonTextArea")
				{
					UIHelper.SetTextInputActive(active: true);
				}
				GUILayout.Space(10f);
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				if (GUILayout.Button("추가 요청", UIStyle.ButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }) && _selectedId != 0L && !string.IsNullOrWhiteSpace(_reason))
				{
					PastaNetwork.RequestAddShitter(_selectedId, _reason);
					HUDManager instance = HUDManager.Instance;
					if (instance != null)
					{
						instance.DisplayTip("Pasta Client", "Shitter 추가 요청 전송됨", false, false, "LC_Tip1");
					}
					_reason = "";
					_selectedId = 0uL;
				}
				if (GUILayout.Button("닫기", UIStyle.ButtonStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
				{
					Close();
				}
				GUILayout.EndHorizontal();
			}
			catch (Exception arg2)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogError((object)$"[ShitterUI] Error in WindowFunc: {arg2}");
				}
			}
			finally
			{
				GUILayout.EndVertical();
				GUI.DragWindow(new Rect(0f, 0f, ((Rect)(ref _windowRect)).width, 20f));
			}
		}

		private static ulong GetSteamIDFromPlayer(PlayerControllerB player, ulong fallbackClientId)
		{
			if ((Object)(object)player == (Object)null)
			{
				return fallbackClientId;
			}
			try
			{
				string[] array = new string[6] { "steamId", "playerSteamId", "ownerClientId", "steamID", "SteamID", "PlayerSteamID" };
				string[] array2 = array;
				foreach (string name in array2)
				{
					FieldInfo field = typeof(PlayerControllerB).GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (!(field != null))
					{
						continue;
					}
					object value = field.GetValue(player);
					if (value != null)
					{
						if (value is ulong num && num != 0)
						{
							return num;
						}
						if (value is long num2 && num2 > 0)
						{
							return (ulong)num2;
						}
					}
				}
				NetworkObject component = ((Component)player).GetComponent<NetworkObject>();
				if ((Object)(object)component != (Object)null)
				{
					ulong ownerClientId = component.OwnerClientId;
					if (ownerClientId > 76561190000000000L && ownerClientId < 76561199999999999L)
					{
						return ownerClientId;
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[ShitterUI] Error getting Steam ID from PlayerControllerB: " + ex.Message));
				}
			}
			if (fallbackClientId > 76561190000000000L && fallbackClientId < 76561199999999999L)
			{
				return fallbackClientId;
			}
			return fallbackClientId;
		}

		private static string GetPlayerNameForUI(PlayerControllerB player, ulong steamId)
		{
			if ((Object)(object)player == (Object)null)
			{
				return "Unknown";
			}
			string text = "Unknown";
			FieldInfo field = typeof(PlayerControllerB).GetField("playerUsername", BindingFlags.Instance | BindingFlags.Public);
			if (field != null)
			{
				string text2 = field.GetValue(player) as string;
				if (!string.IsNullOrEmpty(text2))
				{
					text = text2;
				}
			}
			if (text == "Unknown" && !string.IsNullOrEmpty(((Object)player).name))
			{
				text = ((Object)player).name;
			}
			if (text == "Unknown")
			{
				text = SteamNameFetcher.GetCachedName(steamId);
				if (text == "Unknown")
				{
					SteamNameFetcher.FetchPlayerNameFromGameOrSteam(steamId, delegate
					{
					});
					text = "Loading...";
				}
			}
			return text;
		}

		private static bool IsDefaultPlayerName(string name)
		{
			if (string.IsNullOrEmpty(name) || name == "Unknown" || name == "Loading...")
			{
				return false;
			}
			string text = name.ToLower().Trim();
			if (text.StartsWith("player"))
			{
				string text2 = text.Substring(6).Trim();
				if (string.IsNullOrEmpty(text2))
				{
					return true;
				}
				text2 = text2.Replace("#", "").Replace(" ", "");
				if (text2.Length > 0 && Regex.IsMatch(text2, "^\\d+$"))
				{
					return true;
				}
			}
			if (text == "player")
			{
				return true;
			}
			return false;
		}
	}
	public static class SteamIDHelper
	{
		public static ulong GetSteamID(ulong clientId)
		{
			if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsServer)
			{
				try
				{
					if (NetworkManager.Singleton.ConnectedClients.TryGetValue(clientId, out var value))
					{
						try
						{
							if ((Object)(object)value.PlayerObject != (Object)null)
							{
								PlayerControllerB component = ((Component)value.PlayerObject).GetComponent<PlayerControllerB>();
								if ((Object)(object)component != (Object)null)
								{
									ulong steamIDFromPlayer = GetSteamIDFromPlayer(component);
									if (steamIDFromPlayer != 0L && steamIDFromPlayer != clientId)
									{
										return steamIDFromPlayer;
									}
								}
							}
						}
						catch (Exception ex)
						{
							ManualLogSource log = Plugin.Log;
							if (log != null)
							{
								log.LogWarning((object)("[SteamIDHelper] Error getting Steam ID from NetworkClient: " + ex.Message));
							}
						}
					}
				}
				catch (Exception ex2)
				{
					ManualLogSource log2 = Plugin.Log;
					if (log2 != null)
					{
						log2.LogWarning((object)("[SteamIDHelper] Error accessing ConnectedClients (may be client): " + ex2.Message));
					}
				}
			}
			try
			{
				PlayerControllerB[] array = Object.FindObjectsByType<PlayerControllerB>((FindObjectsSortMode)0);
				PlayerControllerB[] array2 = array;
				foreach (PlayerControllerB val in array2)
				{
					if ((Object)(object)val != (Object)null && val.actualClientId == clientId)
					{
						ulong steamIDFromPlayer2 = GetSteamIDFromPlayer(val);
						if (steamIDFromPlayer2 != 0)
						{
							return steamIDFromPlayer2;
						}
					}
				}
			}
			catch (Exception ex3)
			{
				ManualLogSource log3 = Plugin.Log;
				if (log3 != null)
				{
					log3.LogWarning((object)("[SteamIDHelper] Error searching PlayerControllerB: " + ex3.Message));
				}
			}
			if (clientId > 76561190000000000L && clientId < 76561199999999999L)
			{
				return clientId;
			}
			return clientId;
		}

		private static ulong GetSteamIDFromPlayer(PlayerControllerB player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return 0uL;
			}
			try
			{
				string[] array = new string[6] { "steamId", "playerSteamId", "ownerClientId", "steamID", "SteamID", "PlayerSteamID" };
				string[] array2 = array;
				foreach (string name in array2)
				{
					FieldInfo field = typeof(PlayerControllerB).GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (!(field != null))
					{
						continue;
					}
					object value = field.GetValue(player);
					if (value != null)
					{
						if (value is ulong num && num != 0)
						{
							return num;
						}
						if (value is long num2 && num2 > 0)
						{
							return (ulong)num2;
						}
					}
				}
				if ((Object)(object)((Component)player).GetComponent<NetworkObject>() != (Object)null)
				{
					NetworkObject component = ((Component)player).GetComponent<NetworkObject>();
					if ((Object)(object)component != (Object)null)
					{
						ulong ownerClientId = component.OwnerClientId;
						if (ownerClientId > 76561190000000000L && ownerClientId < 76561199999999999L)
						{
							return ownerClientId;
						}
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("[SteamIDHelper] Error getting Steam ID from PlayerControllerB: " + ex.Message));
				}
			}
			return 0uL;
		}

		public static ulong GetClientID(ulong steamId)
		{
			if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsServer)
			{
				try
				{
					foreach (KeyValuePair<ulong, NetworkClient> connectedClient in NetworkManager.Singleton.ConnectedClients)
					{
						ulong key = connectedClient.Key;
						ulong steamID = GetSteamID(key);
						if (steamID == steamId)
						{
							return key;
						}
					}
				}
				catch (Exception ex)
				{
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogWarning((object)("[SteamIDHelper] Error searching ConnectedClients: " + ex.Message));
					}
				}
			}
			try
			{
				PlayerControllerB[] array = Object.FindObjectsByType<PlayerControllerB>((FindObjectsSortMode)0);
				PlayerControllerB[] array2 = array;
				foreach (PlayerControllerB val in array2)
				{
					if ((Object)(object)val != (Object)null && val.actualClientId != 0)
					{
						ulong steamIDFromPlayer = GetSteamIDFromPlayer(val);
						if (steamIDFromPlayer == steamId)
						{
							return val.actualClientId;
						}
					}
				}
			}
			catch (Exception ex2)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)("[SteamIDHelper] Error searching PlayerControllerB: " + ex2.Message));
				}
			}
			return steamId;
		}
	}
	public static class SteamNameFetcher
	{
		private static readonly Dictionary<ulong, string> _nameCache = new Dictionary<ulong, string>();

		private static readonly Dictionary<ulong, bool> _fetching = new Dictionary<ulong, bool>();

		private static MonoBehaviour? _coroutineRunner;

		public static void Init(MonoBehaviour coroutineRunner)
		{
			_coroutineRunner = coroutineRunner;
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)"[SteamNameFetcher] Initialized");
			}
		}

		public static void FetchPlayerName(ulong steamId, Action<ulong, string>? onComplete = null)
		{
			string value;
			if ((Object)(object)_coroutineRunner == (Object)null)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)"[SteamNameFetcher] CoroutineRunner not initialized!");
				}
			}
			else if (_nameCache.TryGetValue(steamId, out value))
			{
				onComplete?.Invoke(steamId, value);
			}
			else if (_fetching.ContainsKey(steamId) && _fetching[steamId])
			{
				_coroutineRunner.StartCoroutine(WaitForFetch(steamId, onComplete));
			}
			else
			{
				_fetching[steamId] = true;
				_coroutineRunner.StartCoroutine(FetchSteamNameCoroutine(steamId, onComplete));
			}
		}

		private static IEnumerator WaitForFetch(ulong steamId, Action<ulong, string>? onComplete)
		{
			float timeout = 10f;
			float elapsed = 0f;
			while (_fetching.ContainsKey(steamId) && _fetching[steamId] && elapsed < timeout)
			{
				yield return (object)new WaitForSeconds(0.5f);
				elapsed += 0.5f;
				if (_nameCache.TryGetValue(steamId, out string name))
				{
					onComplete?.Invoke(steamId, name);
					yield break;
				}
				name = null;
			}
			if (elapsed >= timeout)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)$"[SteamNameFetcher] Timeout waiting for Steam ID {steamId}");
				}
				onComplete?.Invoke(steamId, "Unknown");
			}
		}

		private static IEnumerator FetchSteamNameCoroutine(ulong steamId, Action<ulong, string>? onComplete)
		{
			string url = $"https://steamcommunity.com/profiles/{steamId}";
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)$"[SteamNameFetcher] Fetching name for Steam ID: {steamId}");
			}
			UnityWebRequest request = UnityWebRequest.Get(url);
			try
			{
				request.SetRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
				yield return request.SendWebRequest();
				string playerName = "Unknown";
				if ((int)request.result == 1)
				{
					try
					{
						string html = request.downloadHandler.text;
						int nameStart = html.IndexOf("<span class=\"actual_persona_name\">");
						if (nameStart >= 0)
						{
							nameStart = html.IndexOf(">", nameStart) + 1;
							int nameEnd3 = html.IndexOf("<", nameStart);
							if (nameEnd3 > nameStart)
							{
								playerName = html.Substring(nameStart, nameEnd3 - nameStart).Trim();
								playerName = DecodeHtmlEntities(playerName);
							}
						}
						if ((playerName == "Unknown" || string.IsNullOrEmpty(playerName)) && nameStart < 0)
						{
							nameStart = html.IndexOf("<div class=\"persona_name\">");
							if (nameStart >= 0)
							{
								nameStart = html.IndexOf(">", nameStart) + 1;
								int nameEnd2 = html.IndexOf("<", nameStart);
								if (nameEnd2 > nameStart)
								{
									playerName = html.Substring(nameStart, nameEnd2 - nameStart).Trim();
									playerName = DecodeHtmlEntities(playerName);
								}
							}
						}
						if ((playerName == "Unknown" || string.IsNullOrEmpty(playerName)) && nameStart < 0)
						{
							nameStart = html.IndexOf("profile_header_actual_link");
							if (nameStart >= 0)
							{
								nameStart = html.IndexOf(">", nameStart) + 1;
								int nameEnd = html.IndexOf("<", nameStart);
								if (nameEnd > nameStart)
								{
									playerName = html.Substring(nameStart, nameEnd - nameStart).Trim();
									playerName = DecodeHtmlEntities(playerName);
								}
							}
						}
						if (string.IsNullOrWhiteSpace(playerName))
						{
							playerName = "Unknown";
						}
					}
					catch (Exception ex2)
					{
						Exception ex = ex2;
						ManualLogSource log2 = Plugin.Log;
						if (log2 != null)
						{
							log2.LogError((object)$"[SteamNameFetcher] Error parsing HTML: {ex}");
						}
						playerName = "Unknown";
					}
				}
				else
				{
					ManualLogSource log3 = Plugin.Log;
					if (log3 != null)
					{
						log3.LogWarning((object)("[SteamNameFetcher] Failed to fetch Steam profile: " + request.error));
					}
				}
				if (!string.IsNullOrEmpty(playerName) && playerName != "Unknown")
				{
					_nameCache[steamId] = playerName;
					ManualLogSource log4 = Plugin.Log;
					if (log4 != null)
					{
						log4.LogInfo((object)$"[SteamNameFetcher] Cached name for {steamId}: {playerName}");
					}
				}
				_fetching[steamId] = false;
				onComplete?.Invoke(steamId, playerName);
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		public static void FetchPlayerNameFromGameOrSteam(ulong steamId, Action<ulong, string>? onComplete = null)
		{
			string playerNameFromGame = GetPlayerNameFromGame(steamId);
			if (!string.IsNullOrEmpty(playerNameFromGame) && playerNameFromGame != "Unknown")
			{
				_nameCache[steamId] = playerNameFromGame;
				onComplete?.Invoke(steamId, playerNameFromGame);
			}
			else
			{
				FetchPlayerName(steamId, onComplete);
			}
		}

		private static string GetPlayerNameFromGame(ulong steamId)
		{
			if ((Object)(object)NetworkManager.Singleton == (Object)null)
			{
				return "Unknown";
			}
			if (NetworkManager.Singleton.IsServer && NetworkManager.Singleton.ConnectedClients != null)
			{
				foreach (KeyValuePair<ulong, NetworkClient> connectedClient in NetworkManager.Singleton.ConnectedClients)
				{
					ulong key = connectedClient.Key;
					ulong steamID = SteamIDHelper.GetSteamID(key);
					if (steamID == steamId)
					{
						NetworkClient value = connectedClient.Value;
						if ((Object)(object)value.PlayerObject != (Object)null)
						{
							string name = ((Object)value.PlayerObject).name;
							if (name != null && !string.IsNullOrEmpty(name) && name != "Player")
							{
								return name;
							}
							break;
						}
						break;
					}
				}
			}
			PlayerControllerB[] array = Object.FindObjectsByType<PlayerControllerB>((FindObjectsSortMode)0);
			PlayerControllerB[] array2 = array;
			foreach (PlayerControllerB val in array2)
			{
				if ((Object)(object)val != (Object)null && val.actualClientId == steamId)
				{
					FieldInfo field = typeof(PlayerControllerB).GetField("playerUsername", BindingFlags.Instance | BindingFlags.Public);
					if (field != null && field.GetValue(val) is string text && !string.IsNullOrEmpty(text))
					{
						return text;
					}
					if (!string.IsNullOrEmpty(((Object)val).name) && ((Object)val).name != "Player")
					{
						return ((Object)val).name;
					}
				}
			}
			return "Unknown";
		}

		public static string GetCachedName(ulong steamId)
		{
			string value;
			return _nameCache.TryGetValue(steamId, out value) ? value : "Unknown";
		}

		public static void CacheName(ulong steamId, string name)
		{
			if (!string.IsNullOrEmpty(name) && name != "Unknown")
			{
				_nameCache[steamId] = name;
			}
		}

		public static void ClearCache()
		{
			_nameCache.Clear();
			_fetching.Clear();
		}

		private static string DecodeHtmlEntities(string html)
		{
			if (string.IsNullOrEmpty(html))
			{
				return html;
			}
			return html.Replace("&amp;", "&").Replace("&lt;", "<").Replace("&gt;", ">")
				.Replace("&quot;", "\"")
				.Replace("&apos;", "'")
				.Replace("&#39;", "'")
				.Replace("&nbsp;", " ");
		}
	}
	public static class UIHelper
	{
		private class UIHelperBehaviour : MonoBehaviour
		{
			private void Update()
			{
				if (IsAnyUIOpen())
				{
					Cursor.visible = true;
					Cursor.lockState = (CursorLockMode)0;
				}
			}

			private void OnGUI()
			{
				_textInputActive = false;
				Action[] array = _drawers.ToArray();
				if (array.Length == 0)
				{
					return;
				}
				Cursor.visible = true;
				Cursor.lockState = (CursorLockMode)0;
				Action[] array2 = array;
				foreach (Action action in array2)
				{
					try
					{
						action();
					}
					catch (Exception ex)
					{
						ManualLogSource log = Plugin.Log;
						if (log != null)
						{
							log.LogError((object)$"[UIHelper] Error in drawer: {ex}");
						}
						ManualLogSource log2 = Plugin.Log;
						if (log2 != null)
						{
							log2.LogError((object)("[UIHelper] Stack trace: " + ex.StackTrace));
						}
					}
				}
			}
		}

		private static readonly List<Action> _drawers = new List<Action>();

		private static UIHelperBehaviour? _behaviour;

		private static bool _textInputActive = false;

		public static void Register(Action draw)
		{
			EnsureInitialized();
			if (!_drawers.Contains(draw))
			{
				_drawers.Add(draw);
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)$"[UIHelper] Registered drawer, total: {_drawers.Count}");
				}
				UpdateCursorState();
			}
		}

		public static void Unregister(Action draw)
		{
			if (_drawers.Contains(draw))
			{
				_drawers.Remove(draw);
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)$"[UIHelper] Unregistered drawer, total: {_drawers.Count}");
				}
				UpdateCursorState();
			}
		}

		public static bool IsAnyUIOpen()
		{
			return _drawers.Count > 0;
		}

		public static bool IsTextInputActive()
		{
			return _textInputActive;
		}

		public static void SetTextInputActive(bool active)
		{
			_textInputActive = active;
		}

		private static void UpdateCursorState()
		{
			if (!((Object)(object)_behaviour == (Object)null) && IsAnyUIOpen())
			{
				Cursor.visible = true;
				Cursor.lockState = (CursorLockMode)0;
			}
		}

		private static void EnsureInitialized()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			if (!((Object)(object)_behaviour != (Object)null))
			{
				GameObject val = new GameObject("PastaUIHelper");
				Object.DontDestroyOnLoad((Object)(object)val);
				_behaviour = val.AddComponent<UIHelperBehaviour>();
				((Object)val).hideFlags = (HideFlags)61;
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)"[UIHelper] UIHelper initialized");
				}
			}
		}
	}
	public static class UIStyle
	{
		private static GUIStyle? _windowStyle;

		private static GUIStyle? _labelStyle;

		private static GUIStyle? _buttonStyle;

		private static GUIStyle? _textFieldStyle;

		private static GUIStyle? _boxStyle;

		private static bool _stylesInitialized = false;

		private static Dictionary<string, Texture2D> _textureCache = new Dictionary<string, Texture2D>();

		public static GUIStyle WindowStyle
		{
			get
			{
				InitializeStyles();
				return _windowStyle;
			}
		}

		public static GUIStyle LabelStyle
		{
			get
			{
				InitializeStyles();
				return _labelStyle;
			}
		}

		public static GUIStyle ButtonStyle
		{
			get
			{
				InitializeStyles();
				return _buttonStyle;
			}
		}

		public static GUIStyle TextFieldStyle
		{
			get
			{
				InitializeStyles();
				return _textFieldStyle;
			}
		}

		public static GUIStyle BoxStyle
		{
			get
			{
				InitializeStyles();
				return _boxStyle;
			}
		}

		public static void InitializeStyles()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: 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_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected O, but got Unknown
			//IL_0083: 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_0096: Expected O, but got Unknown
			//IL_009c: Expected O, but got Unknown
			//IL_00a6: 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)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: 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_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Expected O, but got Unknown
			//IL_00ea: Expected O, but got Unknown
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: 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_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: 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_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01aa: 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_01ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Expected O, but got Unknown
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Expected O, but got Unknown
			//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Expected O, but got Unknown
			//IL_0267: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Expected O, but got Unknown
			//IL_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			//IL_029e: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ae: 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)
			//IL_02bd: Expected O, but got Unknown
			//IL_02be: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: Expected O, but got Unknown
			//IL_02d3: Expected O, but got Unknown
			if (!_stylesInitialized)
			{
				GUIStyle val = new GUIStyle(GUI.skin.window);
				val.normal.background = CreateColorTexture(new Color(0.1f, 0.1f, 0.1f, 0.95f));
				val.onNormal.background = CreateColorTexture(new Color(0.1f, 0.1f, 0.1f, 0.95f));
				val.border = new RectOffset(8, 8, 20, 8);
				val.padding = new RectOffset(10, 10, 25, 10);
				_windowStyle = val;
				GUIStyle val2 = new GUIStyle(GUI.skin.label);
				val2.normal.textColor = Color.white;
				val2.fontSize = 14;
				val2.fontStyle = (FontStyle)0;
				val2.alignment = (TextAnchor)3;
				val2.padding = new RectOffset(5, 5, 5, 5);
				_labelStyle = val2;
				GUIStyle val3 = new GUIStyle(GUI.skin.button);
				val3.normal.background = CreateColorTexture(new Color(0.2f, 0.2f, 0.2f, 1f));
				val3.normal.textColor = Color.white;
				val3.hover.background = CreateColorTexture(new Color(0.3f, 0.3f, 0.3f, 1f));
				val3.hover.textColor = Color.white;
				val3.active.background = CreateColorTexture(new Color(0.15f, 0.15f, 0.15f, 1f));
				val3.active.textColor = Color.white;
				val3.fontSize = 13;
				val3.padding = new RectOffset(10, 10, 5, 5);
				val3.alignment = (TextAnchor)4;
				_buttonStyle = val3;
				GUIStyle val4 = new GUIStyle(GUI.skin.textField);
				val4.normal.background = CreateColorTexture(new Color(0.15f, 0.15f, 0.15f, 1f));
				val4.normal.textColor = Color.white;
				val4.focused.background = CreateColorTexture(new Color(0.2f, 0.2f, 0.2f, 1f));
				val4.focused.textColor = Color.white;
				val4.padding = new RectOffset(5, 5, 5, 5);
				val4.fontSize = 12;
				_textFieldStyle = val4;
				GUIStyle val5 = new GUIStyle(GUI.skin.box);
				val5.normal.background = CreateColorTexture(new Color(0.05f, 0.05f, 0.05f, 0.8f));
				val5.border = new RectOffset(1, 1, 1, 1);
				val5.padding = new RectOffset(5, 5, 5, 5);
				_boxStyle = val5;
				_stylesInitialized = true;
			}
		}

		private static Texture2D CreateColorTexture(Color color)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			string key = $"{color.r}_{color.g}_{color.b}_{color.a}";
			if (_textureCache.TryGetValue(key, out Texture2D value))
			{
				if ((Object)(object)value != (Object)null)
				{
					return value;
				}
				_textureCache.Remove(key);
			}
			Texture2D val = new Texture2D(1, 1, (TextureFormat)4, false);
			val.SetPixel(0, 0, color);
			val.Apply();
			((Object)val).hideFlags = (HideFlags)52;
			_textureCache[key] = val;
			return val;
		}

		public static void ResetStyles()
		{
			_stylesInitialized = false;
			_windowStyle = null;
			_labelStyle = null;
			_buttonStyle = null;
			_textFieldStyle = null;
			_boxStyle = null;
			foreach (Texture2D value in _textureCache.Values)
			{
				if ((Object)(object)value != (Object)null)
				{
					Object.Destroy((Object)(object)value);
				}
			}
			_textureCache.Clear();
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "PastaClient";

		public const string PLUGIN_NAME = "PastaClient";

		public const string PLUGIN_VERSION = "1.2.1";
	}
}
namespace PastaClient.Patches
{
	public class ChatCommandHandler : MonoBehaviour
	{
		private static ChatCommandHandler instance;

		private TMP_InputField? chatInputField;

		private string lastInput = "";

		public static void Init()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			if (!((Object)(object)instance != (Object)null))
			{
				GameObject val = new GameObject("ChatCommandHandler");
				instance = val.AddComponent<ChatCommandHandler>();
				Object.DontDestroyOnLoad((Object)(object)val);
				((Object)val).hideFlags = (HideFlags)61;
			}
		}

		private void Update()
		{
			if (!((Object)(object)HUDManager.Instance == (Object)null) && !((Object)(object)chatInputField != (Object)null))
			{
				FindChatInputField();
				if ((Object)(object)chatInputField != (Object)null)
				{
					SubscribeToChatInput();
				}
			}
		}

		private void FindChatInputField()
		{
			FieldInfo[] fields = typeof(HUDManager).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			FieldInfo[] array = fields;
			foreach (FieldInfo fieldInfo in array)
			{
				object value = fieldInfo.GetValue(HUDManager.Instance);
				TMP_InputField val = (TMP_InputField)((value is TMP_InputField) ? value : null);
				if (val != null)
				{
					chatInputField = val;
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogInfo((object)("[ChatCommandHandler] Found chat input field: " + fieldInfo.Name));
					}
					break;
				}
				InputField val2 = (InputField)((value is InputField) ? value : null);
				if (val2 != null)
				{
					ManualLogSource log2 = Plugin.Log;
					if (log2 != null)
					{
						log2.LogInfo((object)("[ChatCommandHandler] Found UI InputField: " + fieldInfo.Name));
					}
				}
			}
		}

		private void SubscribeToChatInput()
		{
			if (!((Object)(object)chatInputField == (Object)null))
			{
				((UnityEvent<string>)(object)chatInputField.onSubmit).AddListener((UnityAction<string>)OnChatSubmit);
				((UnityEvent<string>)(object)chatInputField.onEndEdit).AddListener((UnityAction<string>)OnChatSubmit);
			}
		}

		private void OnChatSubmit(string input)
		{
			if (!string.IsNullOrWhiteSpace(input) && !(input == lastInput))
			{
				input = input.Trim();
				lastInput = input;
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)("[ChatCommandHandler] Chat submitted: " + input));
				}
				if (ProcessChatCommand(input) && (Object)(object)chatInputField != (Object)null)
				{
					chatInputField.text = "";
					lastInput = "";
				}
			}
		}

		private bool ProcessChatCommand(string input)
		{
			if (input.StartsWith(":st", StringComparison.OrdinalIgnoreCase))
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)"[ChatCommandHandler] :st command detected");
				}
				ShitterUI.Open();
				return true;
			}
			if (input.StartsWith(":who", StringComparison.OrdinalIgnoreCase))
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogInfo((object)"[ChatCommandHandler] :who command detected");
				}
				RecentUI.Open();
				return true;
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "Update")]
	public class PlayerInputPatch
	{
		private static void Prefix(PlayerControllerB __instance, ref bool ___isPlayerDead, ref bool ___isTypingChat)
		{
		}
	}
	[HarmonyPatch(typeof(Input), "GetAxis", new Type[] { typeof(string) })]
	public class InputPatch
	{
		private static bool Prefix(string axisName, ref float __result)
		{
			if (UIHelper.IsTextInputActive())
			{
				__result = 0f;
				return false;
			}
			if (UIHelper.IsAnyUIOpen() && (axisName == "Mouse X" || axisName == "Mouse Y"))
			{
				__result = 0f;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Input), "GetKey", new Type[] { typeof(KeyCode) })]
	public class InputGetKeyPatch
	{
		private static bool Prefix(KeyCode key, ref bool __result)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			if (UIHelper.IsTextInputActive() && (int)key != 27)
			{
				__result = false;
				return false;
			}
			return true;
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}