Decompiled source of SavedServerPasswords v1.1.0

SavedServerPasswords.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace SavedServerPasswords
{
	internal class Entry
	{
		public string Key;

		public string Name;

		public string Password;

		public string Label
		{
			get
			{
				if (!string.IsNullOrEmpty(Name))
				{
					return Name;
				}
				return Key;
			}
		}
	}
	[BepInPlugin("com.slothonmeth.savedserverpasswords", "Saved Server Passwords", "1.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static LogCallback <0>__OnUnityLog;
		}

		public const string Guid = "com.slothonmeth.savedserverpasswords";

		internal static Plugin Instance;

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<bool> AutoSend;

		internal static ConfigEntry<bool> RememberDefault;

		internal static ConfigEntry<float> ButtonOffsetX;

		internal static ConfigEntry<float> ButtonOffsetY;

		internal static bool Remember;

		internal static string PendingName;

		private static readonly Regex JoiningRx = new Regex("Joining server '(.+?)' at ", RegexOptions.Compiled);

		private static readonly List<Entry> Store = new List<Entry>();

		private static string _storePath;

		private static bool _keyDiagLogged;

		internal static IList<Entry> Entries => Store;

		internal static event Action Changed;

		private static void OnUnityLog(string condition, string stackTrace, LogType type)
		{
			Match match = ((condition == null) ? null : JoiningRx.Match(condition));
			if (match != null && match.Success)
			{
				PendingName = match.Groups[1].Value;
			}
		}

		private void Awake()
		{
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Expected O, but got Unknown
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Remember the password you type for a server and reuse it next time.");
			AutoSend = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AutoSend", true, "Send the saved password automatically instead of showing the password prompt. If the server rejects it, the saved entry is deleted and you are prompted again.");
			RememberDefault = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RememberCheckedByDefault", true, "Whether the 'Remember password' checkbox starts ticked.");
			Remember = RememberDefault.Value;
			ButtonOffsetX = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "ButtonOffsetX", 0f, "Nudge the 'Saved passwords' button on the join screen (pixels, right is positive).");
			ButtonOffsetY = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "ButtonOffsetY", 0f, "Nudge the 'Saved passwords' button on the join screen (pixels, up is positive).");
			object obj = <>O.<0>__OnUnityLog;
			if (obj == null)
			{
				LogCallback val = OnUnityLog;
				<>O.<0>__OnUnityLog = val;
				obj = (object)val;
			}
			Application.logMessageReceived += (LogCallback)obj;
			_storePath = Path.Combine(Paths.ConfigPath, "SavedServerPasswords.txt");
			Load();
			((Component)this).gameObject.AddComponent<RememberCheckbox>();
			((Component)this).gameObject.AddComponent<SavedPasswordsUI>();
			Patches.Apply(new Harmony("com.slothonmeth.savedserverpasswords"));
			DumpZNetMembers();
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Loaded. Saved servers: " + Store.Count));
		}

		private static void DumpZNetMembers()
		{
			try
			{
				string[] value = (from m in typeof(ZNet).GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
					select m.Name into n
					where n.IndexOf("assword", StringComparison.OrdinalIgnoreCase) >= 0 || n.IndexOf("dialog", StringComparison.OrdinalIgnoreCase) >= 0 || n.IndexOf("connecting", StringComparison.OrdinalIgnoreCase) >= 0
					select n).Distinct().ToArray();
				Log.LogInfo((object)("ZNet password/dialog members: " + string.Join(", ", value)));
			}
			catch (Exception ex)
			{
				Log.LogError((object)("DumpZNetMembers failed: " + ex));
			}
		}

		internal static string Key(ZRpc rpc)
		{
			try
			{
				if (rpc == null)
				{
					return null;
				}
				object obj = AccessTools.Method(((object)rpc).GetType(), "GetSocket", (Type[])null, (Type[])null)?.Invoke(rpc, null);
				if (obj == null)
				{
					return null;
				}
				string[] array = new string[2] { "GetEndPointString", "GetHostName" };
				foreach (string text in array)
				{
					string text2 = AccessTools.Method(obj.GetType(), text, (Type[])null, (Type[])null)?.Invoke(obj, null) as string;
					if (!string.IsNullOrEmpty(text2))
					{
						return obj.GetType().Name + "|" + text2;
					}
				}
				if (!_keyDiagLogged)
				{
					_keyDiagLogged = true;
					Log.LogWarning((object)("No usable server id on " + obj.GetType().FullName + "; methods: " + string.Join(", ", (from m in obj.GetType().GetMethods()
						select m.Name).Distinct().ToArray())));
				}
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Key() failed: " + ex));
			}
			return null;
		}

		internal static string ServerName()
		{
			try
			{
				FejdStartup instance = FejdStartup.instance;
				if ((Object)(object)instance == (Object)null)
				{
					return null;
				}
				BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
				FieldInfo[] fields = ((object)instance).GetType().GetFields(bindingAttr);
				foreach (FieldInfo fieldInfo in fields)
				{
					if ((fieldInfo.Name.IndexOf("join", StringComparison.OrdinalIgnoreCase) < 0 && fieldInfo.Name.IndexOf("server", StringComparison.OrdinalIgnoreCase) < 0) || typeof(Object).IsAssignableFrom(fieldInfo.FieldType) || fieldInfo.FieldType.IsPrimitive || fieldInfo.FieldType == typeof(string))
					{
						continue;
					}
					object value = fieldInfo.GetValue(instance);
					if (value == null)
					{
						continue;
					}
					string[] array = new string[5] { "m_name", "m_serverName", "serverName", "name", "Name" };
					foreach (string text in array)
					{
						string text2 = (AccessTools.Field(value.GetType(), text)?.GetValue(value) ?? AccessTools.Property(value.GetType(), text)?.GetValue(value, null)) as string;
						if (!string.IsNullOrEmpty(text2))
						{
							return text2;
						}
					}
				}
			}
			catch (Exception ex)
			{
				Log.LogError((object)("ServerName() failed: " + ex));
			}
			return null;
		}

		internal static Entry Find(string key)
		{
			if (key != null)
			{
				return Store.FirstOrDefault((Entry e) => e.Key == key);
			}
			return null;
		}

		internal static bool TryGet(string key, out Entry entry)
		{
			entry = Find(key);
			return entry != null;
		}

		internal static void Save(string key, string name, string password)
		{
			if (key != null && !string.IsNullOrEmpty(password))
			{
				Entry entry = Find(key);
				if (entry == null)
				{
					List<Entry> store = Store;
					Entry obj = new Entry
					{
						Key = key
					};
					entry = obj;
					store.Add(obj);
				}
				else if (entry.Password == password && (name == null || entry.Name == name))
				{
					return;
				}
				entry.Password = password;
				if (!string.IsNullOrEmpty(name))
				{
					entry.Name = name;
				}
				Write();
				Log.LogInfo((object)("Saved password for " + entry.Label + " (" + key + ")"));
			}
		}

		internal static void Forget(string key)
		{
			Entry entry = Find(key);
			if (entry != null)
			{
				Store.Remove(entry);
				Write();
				Log.LogInfo((object)("Forgot password for " + entry.Label));
			}
		}

		internal static void Edit(Entry e, string name, string password)
		{
			e.Name = (string.IsNullOrWhiteSpace(name) ? null : name.Trim());
			if (!string.IsNullOrEmpty(password))
			{
				e.Password = password;
			}
			Write();
		}

		private static void Load()
		{
			try
			{
				if (!File.Exists(_storePath))
				{
					return;
				}
				string[] array = File.ReadAllLines(_storePath);
				for (int i = 0; i < array.Length; i++)
				{
					string[] array2 = array[i].Split(new char[1] { '\t' });
					if (array2.Length >= 2 && array2[0].Length != 0)
					{
						try
						{
							Store.Add(new Entry
							{
								Key = array2[0],
								Password = Encoding.UTF8.GetString(Convert.FromBase64String(array2[1])),
								Name = ((array2.Length > 2 && array2[2].Length > 0) ? Encoding.UTF8.GetString(Convert.FromBase64String(array2[2])) : null)
							});
						}
						catch (FormatException)
						{
						}
					}
				}
			}
			catch (Exception ex2)
			{
				Log.LogError((object)("Loading saved passwords failed: " + ex2));
			}
		}

		private static void Write()
		{
			try
			{
				StringBuilder stringBuilder = new StringBuilder();
				foreach (Entry item in Store)
				{
					stringBuilder.Append(item.Key).Append('\t').Append(Convert.ToBase64String(Encoding.UTF8.GetBytes(item.Password)))
						.Append('\t')
						.AppendLine((item.Name == null) ? "" : Convert.ToBase64String(Encoding.UTF8.GetBytes(item.Name)));
				}
				File.WriteAllText(_storePath, stringBuilder.ToString());
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Writing saved passwords failed: " + ex));
			}
			Plugin.Changed?.Invoke();
		}
	}
	internal static class Patches
	{
		public static void Apply(Harmony harmony)
		{
			Patch(harmony, "RPC_ClientHandshake", null, "HandshakePostfix");
			Patch(harmony, "SendPeerInfo", "SendPeerInfoPrefix");
			Patch(harmony, "RPC_Error", null, "ErrorPostfix");
		}

		private static void Patch(Harmony harmony, string method, string prefix = null, string postfix = null)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(ZNet), method, (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					Plugin.Log.LogWarning((object)("ZNet." + method + " not found; feature disabled."));
					return;
				}
				harmony.Patch((MethodBase)methodInfo, (prefix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(Patches), prefix, (Type[])null), (postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(Patches), postfix, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Plugin.Log.LogInfo((object)("Patched ZNet." + method + " (" + methodInfo?.ToString() + ")"));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Failed to patch ZNet." + method + ": " + ex));
			}
		}

		private static void HandshakePostfix(ZNet __instance, object[] __args)
		{
			try
			{
				if (!Plugin.Enabled.Value || !Plugin.AutoSend.Value)
				{
					return;
				}
				ZRpc val = __args.OfType<ZRpc>().FirstOrDefault();
				bool flag = __args.OfType<bool>().FirstOrDefault();
				if (val == null || !flag || !Plugin.TryGet(Plugin.Key(val), out var entry))
				{
					return;
				}
				BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
				MethodInfo methodInfo = typeof(ZNet).GetMethods(bindingAttr).FirstOrDefault((MethodInfo m) => (m.Name == "OnPasswordEntered" || m.Name == "OnPasswordEnter") && (m.GetParameters().Length == 0 || (m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(string))));
				if (methodInfo != null)
				{
					if (methodInfo.GetParameters().Length == 1)
					{
						methodInfo.Invoke(__instance, new object[1] { entry.Password });
					}
					else
					{
						object? obj = AccessTools.Field(typeof(ZNet), "m_passwordDialog")?.GetValue(__instance);
						Transform val2 = (Transform)((obj is Transform) ? obj : null);
						if ((Object)(object)val2 == (Object)null || !RememberCheckbox.SetFirstInputText(val2, entry.Password))
						{
							return;
						}
						methodInfo.Invoke(__instance, null);
					}
					Plugin.Log.LogInfo((object)("Submitted saved password via ZNet." + methodInfo.Name));
					return;
				}
				MethodInfo methodInfo2 = AccessTools.Method(typeof(ZNet), "SendPeerInfo", (Type[])null, (Type[])null);
				if (methodInfo2 == null)
				{
					return;
				}
				ParameterInfo[] parameters = methodInfo2.GetParameters();
				object[] array = new object[parameters.Length];
				for (int num = 0; num < parameters.Length; num++)
				{
					if (parameters[num].ParameterType == typeof(ZRpc))
					{
						array[num] = val;
						continue;
					}
					if (parameters[num].ParameterType == typeof(string))
					{
						array[num] = entry.Password;
						continue;
					}
					if (parameters[num].HasDefaultValue)
					{
						array[num] = parameters[num].DefaultValue;
						continue;
					}
					return;
				}
				methodInfo2.Invoke(__instance, array);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Auto-send failed, the normal prompt stays: " + ex));
			}
		}

		private static void SendPeerInfoPrefix(object[] __args)
		{
			try
			{
				if (Plugin.Enabled.Value && Plugin.Remember)
				{
					ZRpc? rpc = __args.OfType<ZRpc>().FirstOrDefault();
					Plugin.Save(password: __args.OfType<string>().FirstOrDefault(), key: Plugin.Key(rpc), name: Plugin.PendingName ?? Plugin.ServerName());
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Saving password failed: " + ex));
			}
		}

		private static void ErrorPostfix(object[] __args)
		{
			try
			{
				Type nestedType = typeof(ZNet).GetNestedType("ConnectionStatus");
				for (int i = 0; i < __args.Length; i++)
				{
					if (__args[i] is int num && nestedType != null && Enum.GetName(nestedType, num) == "ErrorPassword")
					{
						Plugin.Forget(Plugin.Key(__args.OfType<ZRpc>().FirstOrDefault()));
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Forgetting password failed: " + ex));
			}
		}
	}
	public class RememberCheckbox : MonoBehaviour
	{
		private const string ObjectName = "SSP_RememberPassword";

		private static readonly Type TmpInputType = AccessTools.TypeByName("TMPro.TMP_InputField");

		private float _nextScan;

		private bool _logged;

		private readonly HashSet<string> _seen = new HashSet<string>();

		private void Update()
		{
			if (Time.unscaledTime < _nextScan || !Plugin.Enabled.Value)
			{
				return;
			}
			_nextScan = Time.unscaledTime + 0.25f;
			try
			{
				Scan();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Checkbox injection failed, disabling it: " + ex));
				((Behaviour)this).enabled = false;
			}
		}

		private void Scan()
		{
			//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Expected O, but got Unknown
			Transform val = null;
			if ((Object)(object)ZNet.instance != (Object)null)
			{
				object? obj = AccessTools.Field(typeof(ZNet), "m_passwordDialog")?.GetValue(ZNet.instance);
				val = (Transform)((obj is Transform) ? obj : null);
			}
			bool flag = (Object)(object)val != (Object)null && ((Component)val).gameObject.activeInHierarchy;
			object obj2 = null;
			if ((Object)(object)FejdStartup.instance != (Object)null)
			{
				obj2 = AccessTools.Field(typeof(FejdStartup), "m_serverPassword")?.GetValue(FejdStartup.instance);
			}
			foreach (Component item in AllInputs())
			{
				if (item != obj2 && item.gameObject.activeInHierarchy && !(((Object)item).name == "FilterField") && !((Object)item).name.StartsWith("SSP_") && !InsideNamed(item.transform, "JoinPanel"))
				{
					bool flag2 = flag && item.transform.IsChildOf(val);
					if (!flag2 && !IsPasswordType(item) && !HasPasswordLabelNearby(item.transform))
					{
						LogOnce(item);
					}
					else if (!((Object)(object)FindDeep(item.transform.parent, "SSP_RememberPassword") != (Object)null))
					{
						Plugin.Log.LogInfo((object)("Adding Remember checkbox to " + ((object)item).GetType().Name + " '" + ((Object)item).name + "' (dialog match: " + flag2 + ")"));
						Build((RectTransform)item.transform);
						return;
					}
				}
			}
			if (!_logged && flag)
			{
				_logged = true;
				Plugin.Log.LogWarning((object)"Password dialog is open but no input field was found under it.");
			}
		}

		private void LogOnce(Component input)
		{
			string text = ((Object)input).name;
			Transform parent = input.transform.parent;
			while ((Object)(object)parent != (Object)null)
			{
				text = ((Object)parent).name + "/" + text;
				parent = parent.parent;
			}
			if (_seen.Add(text))
			{
				Plugin.Log.LogInfo((object)("Input field not matched as password prompt: " + ((object)input).GetType().Name + " " + text));
			}
		}

		private static bool HasPasswordLabelNearby(Transform input)
		{
			Transform parent = input.parent;
			int num = 0;
			while ((Object)(object)parent != (Object)null && num < 3)
			{
				Component[] componentsInChildren = ((Component)parent).GetComponentsInChildren<Component>(false);
				foreach (Component val in componentsInChildren)
				{
					PropertyInfo propertyInfo = (((Object)(object)val == (Object)null) ? null : ((object)val).GetType().GetProperty("text"));
					if (!(propertyInfo == null) && !(propertyInfo.PropertyType != typeof(string)) && !(val is InputField) && !((object)val).GetType().Name.Contains("InputField") && !((Object)(object)val.GetComponentInParent<Button>() != (Object)null) && !InsideNamed(val.transform, "SSP_") && propertyInfo.GetValue(val, null) is string text && text.IndexOf("password", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						return true;
					}
				}
				num++;
				parent = parent.parent;
			}
			return false;
		}

		internal static bool SetFirstInputText(Transform root, string text)
		{
			Component[] componentsInChildren = ((Component)root).GetComponentsInChildren<Component>(true);
			foreach (Component val in componentsInChildren)
			{
				InputField val2 = (InputField)(object)((val is InputField) ? val : null);
				if (val2 != null)
				{
					val2.text = text;
					return true;
				}
				if (TmpInputType != null && TmpInputType.IsInstanceOfType(val))
				{
					PropertyInfo property = ((object)val).GetType().GetProperty("text");
					if (!(property == null))
					{
						property.SetValue(val, text, null);
						return true;
					}
				}
			}
			return false;
		}

		private static IEnumerable<Component> AllInputs()
		{
			InputField[] array = Object.FindObjectsOfType<InputField>();
			for (int i = 0; i < array.Length; i++)
			{
				yield return (Component)(object)array[i];
			}
			if (!(TmpInputType != null))
			{
				yield break;
			}
			foreach (Component item in Object.FindObjectsOfType(TmpInputType).OfType<Component>())
			{
				yield return item;
			}
		}

		private static bool InsideNamed(Transform t, string name)
		{
			while ((Object)(object)t != (Object)null)
			{
				if (((Object)t).name == name || ((Object)t).name.StartsWith("SSP_"))
				{
					return true;
				}
				t = t.parent;
			}
			return false;
		}

		private static bool IsPasswordType(Component input)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Invalid comparison between Unknown and I4
			InputField val = (InputField)(object)((input is InputField) ? input : null);
			if (val != null)
			{
				return (int)val.contentType == 7;
			}
			PropertyInfo property = ((object)input).GetType().GetProperty("contentType");
			if (property != null)
			{
				return property.GetValue(input, null)?.ToString() == "Password";
			}
			return false;
		}

		private static Transform FindDeep(Transform root, string name)
		{
			if ((Object)(object)root == (Object)null)
			{
				return null;
			}
			Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true);
			foreach (Transform val in componentsInChildren)
			{
				if (((Object)val).name == name)
				{
					return val;
				}
			}
			return null;
		}

		private static Font PickFont(Transform near)
		{
			Canvas componentInParent = ((Component)near).GetComponentInParent<Canvas>();
			Text val = ((componentInParent != null) ? ((Component)componentInParent).GetComponentInChildren<Text>(true) : null) ?? Object.FindObjectOfType<Text>();
			if ((Object)(object)val != (Object)null && (Object)(object)val.font != (Object)null)
			{
				return val.font;
			}
			try
			{
				return Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
			}
			catch (Exception)
			{
				return Resources.GetBuiltinResource<Font>("Arial.ttf");
			}
		}

		private static void Build(RectTransform inputRt)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: 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_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Expected O, but got Unknown
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: 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_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d5: Expected O, but got Unknown
			//IL_01d6: 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_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("SSP_RememberPassword", new Type[1] { typeof(RectTransform) });
			RectTransform val2 = (RectTransform)val.transform;
			((Transform)val2).SetParent(((Transform)inputRt).parent, false);
			Vector2 val3 = default(Vector2);
			((Vector2)(ref val3))..ctor(0.5f, 0.5f);
			val2.anchorMax = val3;
			val2.anchorMin = val3;
			val2.pivot = new Vector2(0f, 1f);
			val2.sizeDelta = new Vector2(260f, 28f);
			Vector3[] array = (Vector3[])(object)new Vector3[4];
			inputRt.GetWorldCorners(array);
			float y = ((Transform)val2).lossyScale.y;
			((Transform)val2).position = array[0] + new Vector3(0f, -6f * y, 0f);
			RectTransform obj = NewChild(val, "Box", new Vector2(24f, 24f));
			((Vector2)(ref val3))..ctor(0f, 0.5f);
			obj.anchorMax = val3;
			obj.anchorMin = val3;
			obj.pivot = new Vector2(0f, 0.5f);
			obj.anchoredPosition = new Vector2(2f, 0f);
			Image val4 = ((Component)obj).gameObject.AddComponent<Image>();
			((Graphic)val4).color = new Color(0f, 0f, 0f, 0.7f);
			RectTransform obj2 = NewChild(((Component)obj).gameObject, "Check", new Vector2(14f, 14f));
			((Vector2)(ref val3))..ctor(0.5f, 0.5f);
			obj2.anchorMax = val3;
			obj2.anchorMin = val3;
			obj2.anchoredPosition = Vector2.zero;
			Image val5 = ((Component)obj2).gameObject.AddComponent<Image>();
			((Graphic)val5).color = new Color(1f, 0.72f, 0.2f, 1f);
			RectTransform obj3 = NewChild(val, "Label", Vector2.zero);
			obj3.anchorMin = Vector2.zero;
			obj3.anchorMax = Vector2.one;
			obj3.offsetMin = new Vector2(34f, 0f);
			obj3.offsetMax = Vector2.zero;
			Text obj4 = ((Component)obj3).gameObject.AddComponent<Text>();
			obj4.text = "Remember password";
			obj4.alignment = (TextAnchor)3;
			((Graphic)obj4).color = Color.white;
			obj4.fontSize = 18;
			obj4.font = PickFont((Transform)(object)inputRt);
			((Graphic)obj4).raycastTarget = false;
			Toggle obj5 = val.AddComponent<Toggle>();
			((Selectable)obj5).targetGraphic = (Graphic)(object)val4;
			obj5.graphic = (Graphic)(object)val5;
			obj5.isOn = Plugin.Remember;
			((UnityEvent<bool>)(object)obj5.onValueChanged).AddListener((UnityAction<bool>)delegate(bool v)
			{
				Plugin.Remember = v;
			});
		}

		private static RectTransform NewChild(GameObject parent, string name, Vector2 size)
		{
			//IL_0014: 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_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			RectTransform val = (RectTransform)new GameObject(name, new Type[1] { typeof(RectTransform) }).transform;
			((Transform)val).SetParent(parent.transform, false);
			val.sizeDelta = size;
			return val;
		}
	}
	public class SavedPasswordsUI : MonoBehaviour
	{
		private const string ButtonName = "SSP_Button";

		private const string PanelName = "SSP_Panel";

		private const string IconName = "SSP_Icon";

		private const int MaxRows = 8;

		private static readonly Type TmpTextType = AccessTools.TypeByName("TMPro.TMP_Text");

		private static readonly Type TmpInputType = AccessTools.TypeByName("TMPro.TMP_InputField");

		private float _nextScan;

		private bool _dumped;

		private Transform _join;

		private GameObject _panel;

		private Entry _editing;

		private Component _editInput;

		private bool _reveal;

		private GameObject _buttonTemplate;

		private GameObject _labelTemplate;

		private GameObject _inputTemplate;

		private void OnEnable()
		{
			Plugin.Changed += OnEntriesChanged;
		}

		private void OnDisable()
		{
			Plugin.Changed -= OnEntriesChanged;
		}

		private void OnEntriesChanged()
		{
			if ((Object)(object)_panel != (Object)null && _panel.activeSelf)
			{
				BuildContent();
			}
			UpdateButtonLabel();
		}

		private void Update()
		{
			if (Time.unscaledTime < _nextScan || !Plugin.Enabled.Value)
			{
				return;
			}
			_nextScan = Time.unscaledTime + 0.5f;
			try
			{
				if ((Object)(object)FejdStartup.instance == (Object)null)
				{
					return;
				}
				_join = FindJoinPanel();
				if ((Object)(object)_join == (Object)null || !((Component)_join).gameObject.activeInHierarchy)
				{
					if ((Object)(object)_panel != (Object)null)
					{
						_panel.SetActive(false);
					}
					return;
				}
				if (!_dumped)
				{
					_dumped = true;
					Dump(_join, 0);
				}
				EnsureButton();
				MarkRows();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)("Saved passwords UI failed, disabling it: " + ex));
				((Behaviour)this).enabled = false;
			}
		}

		private void LateUpdate()
		{
			try
			{
				if ((Object)(object)_panel != (Object)null && _panel.activeSelf && Input.GetKeyDown((KeyCode)27))
				{
					_panel.SetActive(false);
				}
			}
			catch (Exception)
			{
			}
		}

		private static Transform FindJoinPanel()
		{
			GameObject val = GameObject.Find("GuiRoot/GUI/StartGui/StartGame/Panel/JoinPanel");
			if ((Object)(object)val != (Object)null)
			{
				return val.transform;
			}
			return (Transform)(object)((IEnumerable<RectTransform>)Object.FindObjectsOfType<RectTransform>()).FirstOrDefault((Func<RectTransform, bool>)((RectTransform t) => ((Object)t).name == "JoinPanel"));
		}

		private static string TextOf(Component c)
		{
			Text val = (Text)(object)((c is Text) ? c : null);
			if (val == null)
			{
				return ((object)c).GetType().GetProperty("text")?.GetValue(c, null) as string;
			}
			return val.text;
		}

		private static bool SetText(Component c, string value)
		{
			Text val = (Text)(object)((c is Text) ? c : null);
			if (val != null)
			{
				val.text = value;
				return true;
			}
			PropertyInfo property = ((object)c).GetType().GetProperty("text");
			if (property == null || property.PropertyType != typeof(string))
			{
				return false;
			}
			property.SetValue(c, value, null);
			return true;
		}

		private static IEnumerable<Component> TextsIn(Transform root)
		{
			Component[] componentsInChildren = ((Component)root).GetComponentsInChildren<Component>(true);
			foreach (Component val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && (val is Text || (TmpTextType != null && TmpTextType.IsInstanceOfType(val))))
				{
					yield return val;
				}
			}
		}

		private static bool IsInputField(Component c)
		{
			if (!(c is InputField))
			{
				if (TmpInputType != null)
				{
					return TmpInputType.IsInstanceOfType(c);
				}
				return false;
			}
			return true;
		}

		private void Dump(Transform t, int depth)
		{
			//IL_0098: 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_00c0: 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_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Expected O, but got Unknown
			if (depth == 0)
			{
				Plugin.Log.LogInfo((object)"Join screen layout (for UI placement):");
			}
			string text = string.Join(" ", (from c in ((Component)t).GetComponents<Component>()
				where (Object)(object)c != (Object)null && !(c is Transform)
				select ((object)c).GetType().Name).ToArray());
			RectTransform val = (RectTransform)(object)((t is RectTransform) ? t : null);
			object obj;
			if (!((Object)(object)val != (Object)null))
			{
				obj = "";
			}
			else
			{
				string[] obj2 = new string[5] { " [", null, null, null, null };
				Rect rect = val.rect;
				obj2[1] = Mathf.RoundToInt(((Rect)(ref rect)).width).ToString();
				obj2[2] = "x";
				rect = val.rect;
				obj2[3] = Mathf.RoundToInt(((Rect)(ref rect)).height).ToString();
				obj2[4] = "]";
				obj = string.Concat(obj2);
			}
			string text2 = (string)obj;
			string text3 = null;
			Component[] components = ((Component)t).GetComponents<Component>();
			foreach (Component val2 in components)
			{
				if ((Object)(object)val2 != (Object)null)
				{
					string text4 = TextOf(val2);
					if (text4 != null && (val2 is Text || (TmpTextType != null && TmpTextType.IsInstanceOfType(val2))))
					{
						text3 = text4;
						break;
					}
				}
			}
			Plugin.Log.LogInfo((object)(new string(' ', depth * 2) + ((Object)t).name + (((Component)t).gameObject.activeSelf ? "" : " (inactive)") + text2 + " " + text + ((text3 != null) ? (" text='" + text3.Replace("\n", " ") + "'") : "")));
			if (depth >= 4)
			{
				return;
			}
			foreach (Transform item in t)
			{
				Transform t2 = item;
				Dump(t2, depth + 1);
			}
		}

		private Button FindButton(params string[] keys)
		{
			Button[] componentsInChildren = ((Component)_join).GetComponentsInChildren<Button>(false);
			foreach (Button val in componentsInChildren)
			{
				if (((Object)val).name.StartsWith("SSP_"))
				{
					continue;
				}
				string text = TextsIn(((Component)val).transform).Select(TextOf).FirstOrDefault((string t) => !string.IsNullOrEmpty(t)) ?? "";
				foreach (string value in keys)
				{
					if (((Object)val).name.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0)
					{
						return val;
					}
				}
			}
			return null;
		}

		private void CaptureTemplates()
		{
			Button val = FindButton("back") ?? ((IEnumerable<Button>)((Component)_join).GetComponentsInChildren<Button>(false)).FirstOrDefault((Func<Button, bool>)((Button b) => !((Object)b).name.StartsWith("SSP_") && TextsIn(((Component)b).transform).Any()));
			if ((Object)(object)val != (Object)null)
			{
				_buttonTemplate = ((Component)val).gameObject;
			}
			foreach (Component item in TextsIn(_join))
			{
				if (!((Object)(object)item.GetComponentInParent<Button>() != (Object)null) && item.transform.IsChildOf(_join) && !item.GetComponentsInParent<Component>(true).Any(IsInputField) && !((Object)item).name.StartsWith("SSP_") && !((Object)item.GetComponentInParent<RectTransform>()).name.StartsWith("SSP_"))
				{
					_labelTemplate = item.gameObject;
					break;
				}
			}
			Component[] componentsInChildren = ((Component)_join).GetComponentsInChildren<Component>(true);
			foreach (Component val2 in componentsInChildren)
			{
				if ((Object)(object)val2 != (Object)null && IsInputField(val2) && !((Object)val2).name.StartsWith("SSP_"))
				{
					_inputTemplate = val2.gameObject;
					break;
				}
			}
		}

		private static bool IsTextOrNull(Component c)
		{
			if ((Object)(object)c != (Object)null)
			{
				if (!(c is Text))
				{
					if (TmpTextType != null)
					{
						return TmpTextType.IsInstanceOfType(c);
					}
					return false;
				}
				return true;
			}
			return false;
		}

		private static GameObject Clone(GameObject template, Transform parent, string name)
		{
			GameObject val = Object.Instantiate<GameObject>(template, parent, false);
			((Object)val).name = name;
			Component[] componentsInChildren = val.GetComponentsInChildren<Component>(true);
			foreach (Component val2 in componentsInChildren)
			{
				if ((Object)(object)val2 != (Object)null && ((object)val2).GetType().Name == "Localize")
				{
					Object.DestroyImmediate((Object)(object)val2);
				}
			}
			val.SetActive(true);
			return val;
		}

		private static void Position(GameObject go, float x, float y, float w, float h)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = (RectTransform)go.transform;
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(0.5f, 0.5f);
			val.pivot = val2;
			Vector2 anchorMin = (val.anchorMax = val2);
			val.anchorMin = anchorMin;
			val.anchoredPosition = new Vector2(x, y);
			val.sizeDelta = new Vector2(w, h);
		}

		private GameObject MakeButton(Transform parent, string label, float x, float y, float w, float h, UnityAction onClick)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			GameObject val = Clone(_buttonTemplate, parent, "SSP_Btn_" + label);
			Button component = val.GetComponent<Button>();
			component.onClick = new ButtonClickedEvent();
			((UnityEvent)component.onClick).AddListener(onClick);
			foreach (Component item in TextsIn(val.transform))
			{
				SetText(item, label);
			}
			Position(val, x, y, w, h);
			return val;
		}

		private GameObject MakeLabel(Transform parent, string text, float x, float y, float w, float h, bool left)
		{
			GameObject val = Clone(_labelTemplate ?? _buttonTemplate, parent, "SSP_Label");
			Button[] componentsInChildren = val.GetComponentsInChildren<Button>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
			}
			foreach (Component item in TextsIn(val.transform))
			{
				SetText(item, text);
				SetAlignLeft(item, left);
			}
			Position(val, x, y, w, h);
			return val;
		}

		private static void SetAlignLeft(Component text, bool left)
		{
			try
			{
				Text val = (Text)(object)((text is Text) ? text : null);
				if (val != null)
				{
					val.alignment = (TextAnchor)(left ? 3 : 4);
					return;
				}
				PropertyInfo property = ((object)text).GetType().GetProperty("alignment");
				if (!(property == null))
				{
					property.SetValue(text, Enum.Parse(property.PropertyType, left ? "MidlineLeft" : "Midline"), null);
				}
			}
			catch (Exception)
			{
			}
		}

		private void EnsureButton()
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Expected O, but got Unknown
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Expected O, but got Unknown
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Expected O, but got Unknown
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Expected O, but got Unknown
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: 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_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: 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_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: 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_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_buttonTemplate == (Object)null || (Object)(object)_labelTemplate == (Object)null || (Object)(object)_inputTemplate == (Object)null)
			{
				CaptureTemplates();
			}
			if ((Object)(object)_buttonTemplate == (Object)null)
			{
				return;
			}
			Transform parent = _buttonTemplate.transform.parent;
			if ((Object)(object)parent == (Object)null || (Object)(object)parent.Find("SSP_Button") != (Object)null)
			{
				return;
			}
			GameObject obj = Clone(_buttonTemplate, parent, "SSP_Button");
			Button component = obj.GetComponent<Button>();
			component.onClick = new ButtonClickedEvent();
			((UnityEvent)component.onClick).AddListener(new UnityAction(TogglePanel));
			RectTransform val = (RectTransform)_buttonTemplate.transform;
			RectTransform val2 = (RectTransform)obj.transform;
			Button val3 = FindButton("connect");
			bool flag = false;
			Rect rect;
			if ((Object)(object)val3 != (Object)null && (Object)(object)((Component)val3).gameObject != (Object)(object)_buttonTemplate)
			{
				Vector3[] array = (Vector3[])(object)new Vector3[4];
				Vector3[] array2 = (Vector3[])(object)new Vector3[4];
				val.GetWorldCorners(array);
				((RectTransform)((Component)val3).transform).GetWorldCorners(array2);
				float x = array[2].x;
				float x2 = array2[0].x;
				float num = ((((Transform)val2).lossyScale.x > 0f) ? ((Transform)val2).lossyScale.x : 1f);
				float num2 = (x2 - x) / num;
				if (num2 > 60f)
				{
					float num3 = num2 - 12f;
					rect = val.rect;
					float num4 = Mathf.Min(num3, ((Rect)(ref rect)).width);
					rect = val.rect;
					val2.sizeDelta = new Vector2(num4, ((Rect)(ref rect)).height);
					((Transform)val2).position = new Vector3((x + x2) * 0.5f, (array[0].y + array[1].y) * 0.5f, array[0].z);
					val2.anchoredPosition += new Vector2(Plugin.ButtonOffsetX.Value, Plugin.ButtonOffsetY.Value);
					flag = true;
				}
			}
			if (!flag)
			{
				Vector2 anchoredPosition = val.anchoredPosition;
				float value = Plugin.ButtonOffsetX.Value;
				rect = val.rect;
				val2.anchoredPosition = anchoredPosition + new Vector2(value, 0f - (((Rect)(ref rect)).height + 8f) + Plugin.ButtonOffsetY.Value);
			}
			UpdateButtonLabel();
			Plugin.Log.LogInfo((object)("Added 'Saved passwords' button (cloned from '" + ((Object)_buttonTemplate).name + "')."));
		}

		private void UpdateButtonLabel()
		{
			Transform val = (((Object)(object)_buttonTemplate != (Object)null) ? _buttonTemplate.transform.parent : null);
			Transform val2 = (((Object)(object)val != (Object)null) ? val.Find("SSP_Button") : null);
			if ((Object)(object)val2 == (Object)null)
			{
				return;
			}
			foreach (Component item in TextsIn(val2))
			{
				SetText(item, "Passwords (" + Plugin.Entries.Count + ")");
			}
		}

		private void TogglePanel()
		{
			if ((Object)(object)_panel == (Object)null)
			{
				CreatePanel();
			}
			if (!((Object)(object)_panel == (Object)null))
			{
				_panel.SetActive(!_panel.activeSelf);
				if (_panel.activeSelf)
				{
					_editing = null;
					BuildContent();
				}
			}
		}

		private void CreatePanel()
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_buttonTemplate == (Object)null))
			{
				Canvas componentInParent = ((Component)_join).GetComponentInParent<Canvas>();
				Transform val = (((Object)(object)componentInParent != (Object)null) ? ((Component)componentInParent.rootCanvas).transform : _join.root);
				_panel = new GameObject("SSP_Panel", new Type[1] { typeof(RectTransform) });
				_panel.transform.SetParent(val, false);
				_panel.transform.SetAsLastSibling();
				Image val2 = _panel.AddComponent<Image>();
				Rect rect = ((RectTransform)_join).rect;
				float width = ((Rect)(ref rect)).width;
				rect = ((RectTransform)_join).rect;
				float joinArea = width * ((Rect)(ref rect)).height;
				Image val3 = ((IEnumerable<Image>)(from i in ((Component)_join).GetComponentsInParent<Image>(true)
					where (Object)(object)i.sprite != (Object)null
					select i).OrderBy(delegate(Image i)
				{
					//IL_0006: Unknown result type (might be due to invalid IL or missing references)
					//IL_000b: Unknown result type (might be due to invalid IL or missing references)
					//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)
					Rect rect2 = ((Graphic)i).rectTransform.rect;
					float width2 = ((Rect)(ref rect2)).width;
					rect2 = ((Graphic)i).rectTransform.rect;
					return width2 * ((Rect)(ref rect2)).height;
				})).FirstOrDefault((Func<Image, bool>)delegate(Image i)
				{
					//IL_0006: Unknown result type (might be due to invalid IL or missing references)
					//IL_000b: Unknown result type (might be due to invalid IL or missing references)
					//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)
					Rect rect2 = ((Graphic)i).rectTransform.rect;
					float width2 = ((Rect)(ref rect2)).width;
					rect2 = ((Graphic)i).rectTransform.rect;
					return width2 * ((Rect)(ref rect2)).height >= joinArea * 0.9f;
				}) ?? ((IEnumerable<Image>)((Component)_join).GetComponentsInParent<Image>(true)).FirstOrDefault((Func<Image, bool>)((Image i) => (Object)(object)i.sprite != (Object)null));
				if ((Object)(object)val3 != (Object)null)
				{
					Plugin.Log.LogInfo((object)("Panel background copied from '" + ((Object)val3).name + "' (sprite '" + ((Object)val3.sprite).name + "')"));
				}
				if ((Object)(object)val3 != (Object)null)
				{
					val2.sprite = val3.sprite;
					val2.type = val3.type;
					((Graphic)val2).material = ((Graphic)val3).material;
					((Graphic)val2).color = ((Graphic)val3).color;
				}
				else
				{
					((Graphic)val2).color = new Color(0.18f, 0.11f, 0.06f, 0.97f);
				}
				((Graphic)val2).raycastTarget = true;
			}
		}

		private void BuildContent()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Expected O, but got Unknown
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_0248: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Expected O, but got Unknown
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0286: Expected O, but got Unknown
			//IL_030f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0319: Expected O, but got Unknown
			//IL_0344: Unknown result type (might be due to invalid IL or missing references)
			//IL_034e: Expected O, but got Unknown
			//IL_040e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0418: Expected O, but got Unknown
			//IL_0442: Unknown result type (might be due to invalid IL or missing references)
			//IL_044c: Expected O, but got Unknown
			if ((Object)(object)_panel == (Object)null)
			{
				return;
			}
			foreach (Transform item in _panel.transform)
			{
				Object.Destroy((Object)(object)((Component)item).gameObject);
			}
			_editInput = null;
			List<Entry> list = Plugin.Entries.Take(8).ToList();
			float num = 46f;
			float num2 = 150f + (float)Math.Max(list.Count, 1) * num + 50f;
			Position(_panel, 0f, 0f, 600f, num2);
			RectTransform val = (RectTransform)_join;
			Transform transform = _panel.transform;
			Rect rect = val.rect;
			transform.position = ((Transform)val).TransformPoint(Vector2.op_Implicit(((Rect)(ref rect)).center));
			float num3 = num2 / 2f - 40f;
			MakeLabel(_panel.transform, "Saved server passwords (" + Plugin.Entries.Count + ")", 0f, num3, 560f, 36f, left: false);
			num3 -= 52f;
			if (list.Count == 0)
			{
				MakeLabel(_panel.transform, "Nothing saved yet. Join a server and tick 'Remember password'.", 0f, num3 - 20f, 560f, 60f, left: false);
			}
			foreach (Entry item2 in list)
			{
				Entry entry = item2;
				MakeLabel(_panel.transform, entry.Label, -190f, num3, 210f, 36f, left: true);
				if (_editing == entry)
				{
					_editInput = MakeInput(_panel.transform, entry.Password, -20f, num3, 150f, 36f);
					MakeButton(_panel.transform, "Save", 120f, num3, 80f, 36f, (UnityAction)delegate
					{
						string password = (((Object)(object)_editInput != (Object)null) ? TextOf(_editInput) : null);
						Plugin.Edit(entry, entry.Name, password);
						_editing = null;
						BuildContent();
					});
					MakeButton(_panel.transform, "Cancel", 215f, num3, 80f, 36f, (UnityAction)delegate
					{
						_editing = null;
						BuildContent();
					});
				}
				else
				{
					MakeLabel(_panel.transform, _reveal ? entry.Password : new string('*', Math.Min(entry.Password.Length, 12)), -20f, num3, 150f, 36f, left: true);
					MakeButton(_panel.transform, "Edit", 120f, num3, 80f, 36f, (UnityAction)delegate
					{
						_editing = entry;
						BuildContent();
					});
					MakeButton(_panel.transform, "Delete", 215f, num3, 80f, 36f, (UnityAction)delegate
					{
						_editing = null;
						Plugin.Forget(entry.Key);
					});
				}
				num3 -= num;
			}
			if (Plugin.Entries.Count > 8)
			{
				MakeLabel(_panel.transform, "+" + (Plugin.Entries.Count - 8) + " more (edit the file to manage them)", 0f, num3, 560f, 30f, left: false);
			}
			float y = (0f - num2) / 2f + 40f;
			MakeButton(_panel.transform, _reveal ? "Hide passwords" : "Show passwords", -140f, y, 240f, 40f, (UnityAction)delegate
			{
				_reveal = !_reveal;
				BuildContent();
			});
			MakeButton(_panel.transform, "Close", 140f, y, 240f, 40f, (UnityAction)delegate
			{
				_panel.SetActive(false);
			});
		}

		private Component MakeInput(Transform parent, string text, float x, float y, float w, float h)
		{
			if ((Object)(object)_inputTemplate == (Object)null)
			{
				return null;
			}
			GameObject val = Clone(_inputTemplate, parent, "SSP_Input");
			Component[] componentsInChildren = val.GetComponentsInChildren<Component>(true);
			foreach (Component val2 in componentsInChildren)
			{
				if ((Object)(object)val2 == (Object)null || !IsInputField(val2))
				{
					continue;
				}
				string[] array = new string[6] { "onValueChanged", "onEndEdit", "onSubmit", "onSelect", "onDeselect", "onValueChange" };
				foreach (string name in array)
				{
					PropertyInfo property = ((object)val2).GetType().GetProperty(name);
					if (property != null && property.CanWrite)
					{
						try
						{
							property.SetValue(val2, Activator.CreateInstance(property.PropertyType), null);
						}
						catch (Exception)
						{
						}
					}
				}
				SetText(val2, text);
				Position(val, x, y, w, h);
				return val2;
			}
			return null;
		}

		private void MarkRows()
		{
			HashSet<string> hashSet = new HashSet<string>(from e in Plugin.Entries
				where !string.IsNullOrEmpty(e.Name)
				select e.Name);
			foreach (Component item in FindTexts())
			{
				if (!item.gameObject.activeInHierarchy || item.transform.IsChildOf(((Object)(object)_panel != (Object)null) ? _panel.transform : null))
				{
					continue;
				}
				string text = TextOf(item);
				bool flag = !string.IsNullOrEmpty(text) && hashSet.Contains(text.Trim());
				Transform parent = item.transform.parent;
				if (!((Object)(object)parent == (Object)null))
				{
					Transform val = parent.Find("SSP_Icon_" + ((Object)item).GetInstanceID());
					if (flag && (Object)(object)val == (Object)null)
					{
						AddIcon(item, parent);
					}
					else if (!flag && (Object)(object)val != (Object)null)
					{
						Object.Destroy((Object)(object)((Component)val).gameObject);
					}
				}
			}
		}

		private static IEnumerable<Component> FindTexts()
		{
			Text[] array = Object.FindObjectsOfType<Text>();
			for (int i = 0; i < array.Length; i++)
			{
				yield return (Component)(object)array[i];
			}
			if (!(TmpTextType != null))
			{
				yield break;
			}
			foreach (Component item in Object.FindObjectsOfType(TmpTextType).OfType<Component>())
			{
				yield return item;
			}
		}

		private void AddIcon(Component label, Transform host)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: 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_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("SSP_Icon_" + ((Object)label).GetInstanceID(), new Type[1] { typeof(RectTransform) });
			RectTransform val2 = (RectTransform)val.transform;
			((Transform)val2).SetParent(host, false);
			Vector2 val3 = default(Vector2);
			((Vector2)(ref val3))..ctor(0.5f, 0.5f);
			val2.anchorMax = val3;
			val2.anchorMin = val3;
			val2.pivot = new Vector2(1f, 0.5f);
			val2.sizeDelta = new Vector2(22f, 16f);
			RectTransform val4 = (RectTransform)label.transform;
			Vector3[] array = (Vector3[])(object)new Vector3[4];
			val4.GetWorldCorners(array);
			((Transform)val2).position = new Vector3(array[0].x - 2f * ((Transform)val2).lossyScale.x, (array[0].y + array[1].y) * 0.5f, array[0].z);
			Image obj = val.AddComponent<Image>();
			((Graphic)obj).color = new Color(1f, 0.72f, 0.2f, 0.95f);
			((Graphic)obj).raycastTarget = false;
			Graphic val5 = MakeTagLabel((Transform)(object)val2, label);
			if ((Object)(object)val5 != (Object)null)
			{
				val5.raycastTarget = false;
			}
		}

		private static Graphic MakeTagLabel(Transform parent, Component styleSource)
		{
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: 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_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = Object.Instantiate<GameObject>(styleSource.gameObject, parent, false);
			((Object)val).name = "SSP_Tag";
			Component[] componentsInChildren = val.GetComponentsInChildren<Component>(true);
			foreach (Component val2 in componentsInChildren)
			{
				if ((Object)(object)val2 != (Object)null && ((object)val2).GetType().Name == "Localize")
				{
					Object.DestroyImmediate((Object)(object)val2);
				}
			}
			foreach (Component item in TextsIn(val.transform))
			{
				SetText(item, "PW");
				SetFontSize(item, 11f);
			}
			RectTransform val3 = (RectTransform)val.transform;
			val3.anchorMin = Vector2.zero;
			val3.anchorMax = Vector2.one;
			Vector2 offsetMin = (val3.offsetMax = Vector2.zero);
			val3.offsetMin = offsetMin;
			return val.GetComponent<Graphic>();
		}

		private static void SetFontSize(Component text, float size)
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Text val = (Text)(object)((text is Text) ? text : null);
				if (val != null)
				{
					val.fontSize = (int)size;
					return;
				}
				((object)text).GetType().GetProperty("enableAutoSizing")?.SetValue(text, false, null);
				((object)text).GetType().GetProperty("fontSize")?.SetValue(text, size, null);
				((object)text).GetType().GetProperty("color")?.SetValue(text, Color.black, null);
			}
			catch (Exception)
			{
			}
		}
	}
}