Decompiled source of AutoConnector v1.0.0

plugins/AutoConnector.dll

Decompiled 4 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Permissions;
using AutoConnector.Common;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GUIFramework;
using HarmonyLib;
using Jotunn.Managers;
using Jotunn.Utils;
using TMPro;
using UnityEngine;
using YamlDotNet.Core;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("AutoConnector")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("AutoConnector")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
namespace AutoConnector
{
	[BepInPlugin("MidnightsFX.Autoconnect", "AutoConnector", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	internal class AutoConnector : BaseUnityPlugin
	{
		public const string PluginGUID = "MidnightsFX.Autoconnect";

		public const string PluginName = "AutoConnector";

		public const string PluginVersion = "1.0.0";

		internal static ManualLogSource Log;

		internal ValConfig cfg;

		public void Awake()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			cfg = new ValConfig(((BaseUnityPlugin)this).Config);
			if (!GUIManager.IsHeadless())
			{
				ServerStore.Init();
				new Harmony("MidnightsFX.Autoconnect").PatchAll(Assembly.GetExecutingAssembly());
			}
		}
	}
	internal class Logger
	{
		public static LogLevel Level = (LogLevel)16;

		public static void EnableDebugLogging(object sender, EventArgs e)
		{
			CheckEnableDebugLogging();
		}

		public static void CheckEnableDebugLogging()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (ValConfig.EnableDebugMode.Value)
			{
				Level = (LogLevel)32;
			}
			else
			{
				Level = (LogLevel)16;
			}
		}

		public static void SetDebugLogging(bool state)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			if (state)
			{
				Level = (LogLevel)32;
			}
			else
			{
				Level = (LogLevel)16;
			}
		}

		public static void LogDebug(string message)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)Level >= 32)
			{
				AutoConnector.Log.LogInfo((object)("[DEBUG]" + message));
			}
		}

		public static void LogInfo(string message)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)Level >= 16)
			{
				AutoConnector.Log.LogInfo((object)message);
			}
		}

		public static void LogWarning(string message)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			if ((int)Level >= 4)
			{
				AutoConnector.Log.LogWarning((object)message);
			}
		}

		public static void LogError(string message)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			if ((int)Level >= 2)
			{
				AutoConnector.Log.LogError((object)message);
			}
		}
	}
	internal class ValConfig
	{
		public static ConfigFile cfg;

		public static ConfigEntry<bool> EnableDebugMode;

		public static readonly string cfgFolder = "AutoConnector";

		public ValConfig(ConfigFile cf)
		{
			cfg = cf;
			cfg.SaveOnConfigSet = true;
			CreateConfigValues(cf);
			Logger.SetDebugLogging(EnableDebugMode.Value);
		}

		private void CreateConfigValues(ConfigFile Config)
		{
			//IL_001a: 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_002c: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Expected O, but got Unknown
			EnableDebugMode = Config.Bind<bool>("Client config", "EnableDebugMode", false, new ConfigDescription("Enables Debug logging.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdvanced = true
			} }));
			EnableDebugMode.SettingChanged += Logger.EnableDebugLogging;
			Logger.CheckEnableDebugLogging();
		}
	}
}
namespace AutoConnector.Patches
{
	internal static class Favorites
	{
		[HarmonyPatch(typeof(ServerListGui), "Initialize")]
		internal static class AddSavedServers
		{
			[HarmonyPostfix]
			private static void Postfix(ServerListGui __instance)
			{
				//IL_003a: 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_005b: Unknown result type (might be due to invalid IL or missing references)
				LocalServerList favoriteServersList = __instance.m_favoriteServersList;
				if (favoriteServersList == null)
				{
					return;
				}
				int num = 0;
				foreach (SavedServer server in ServerStore.Servers)
				{
					if (!((ServerJoinData)(ref server.JoinData)).IsValid)
					{
						continue;
					}
					if (server.HasOwnName)
					{
						NameServer(server.JoinData, server.Name);
						foreach (ServerJoinData aliasJoinDatum in server.AliasJoinData)
						{
							NameServer(aliasJoinDatum, server.Name);
						}
					}
					if (!AlreadyListed(favoriteServersList, server))
					{
						favoriteServersList.Add(server.JoinData);
						num++;
					}
				}
				if (num > 0)
				{
					Logger.LogInfo($"Added {num} saved server(s) to favorites.");
				}
			}

			private static void NameServer(ServerJoinData server, string name)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				MultiBackendMatchmaking.SetServerName(server, new ServerNameAtTimePoint(name, DateTime.MaxValue));
			}

			private static bool AlreadyListed(LocalServerList favorites, SavedServer saved)
			{
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_0025: 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)
				if (favorites.Contains(saved.JoinData))
				{
					return true;
				}
				foreach (ServerJoinData aliasJoinDatum in saved.AliasJoinData)
				{
					if (favorites.Contains(aliasJoinDatum))
					{
						return true;
					}
				}
				return false;
			}
		}
	}
	internal static class PasswordFlow
	{
		private sealed class Rejection
		{
			internal readonly ServerJoinData Server;

			internal readonly string Name;

			internal readonly bool WasSaved;

			internal Rejection(ServerJoinData server, string name, bool wasSaved)
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				Server = server;
				Name = name;
				WasSaved = wasSaved;
			}
		}

		[HarmonyPatch(typeof(FejdStartup), "JoinServer")]
		internal static class CaptureJoinTarget
		{
			[HarmonyPrefix]
			private static void Prefix(FejdStartup __instance)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_0031: Unknown result type (might be due to invalid IL or missing references)
				//IL_0036: Unknown result type (might be due to invalid IL or missing references)
				joinTarget = __instance.m_joinServer;
				joinName = NameOf(joinTarget);
				sentPassword = null;
				if (retryTarget != joinTarget)
				{
					retryTarget = ServerJoinData.None;
					retryPassword = null;
				}
			}
		}

		[HarmonyPatch(typeof(ZNet), "RPC_ClientHandshake")]
		internal static class SupplyPassword
		{
			[HarmonyPrefix]
			private static void Prefix(bool needPassword, out PasswordLoan __state)
			{
				__state = null;
				if (needPassword && ((ServerJoinData)(ref joinTarget)).IsValid)
				{
					string text = TakeRetryPassword() ?? SavedPassword();
					if (text != null)
					{
						__state = new PasswordLoan(FejdStartup.ServerPassword);
						FejdStartup.ServerPassword = text;
					}
				}
			}

			[HarmonyPostfix]
			private static void Postfix(PasswordLoan __state)
			{
				if (__state != null)
				{
					FejdStartup.ServerPassword = __state.Displaced;
				}
			}
		}

		internal sealed class PasswordLoan
		{
			internal readonly string Displaced;

			internal PasswordLoan(string displaced)
			{
				Displaced = displaced;
			}
		}

		[HarmonyPatch(typeof(ZNet), "SendPeerInfo")]
		internal static class RecordSentPassword
		{
			[HarmonyPrefix]
			private static void Prefix(ZNet __instance, string password)
			{
				if (!__instance.IsServer() && !string.IsNullOrEmpty(password))
				{
					sentPassword = password;
				}
			}
		}

		[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
		internal static class SaveAcceptedPassword
		{
			[HarmonyPostfix]
			private static void Postfix(ZNet __instance)
			{
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Invalid comparison between Unknown and I4
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_003e: Unknown result type (might be due to invalid IL or missing references)
				if (!__instance.IsServer() && sentPassword != null && (int)ZNet.GetConnectionStatus() == 2)
				{
					if (((ServerJoinData)(ref joinTarget)).IsValid)
					{
						ServerStore.Remember(joinTarget, joinName, sentPassword);
						rejected.Remove(joinTarget);
					}
					sentPassword = null;
				}
			}
		}

		[HarmonyPatch(typeof(ZNet), "RPC_Error")]
		internal static class NoteRejectedPassword
		{
			[HarmonyPostfix]
			private static void Postfix(int error)
			{
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				//IL_004e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0037: 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)
				if (error == 6 && sentPassword != null && ((ServerJoinData)(ref joinTarget)).IsValid)
				{
					if (!rejected.TryGetValue(joinTarget, out var value))
					{
						value = new HashSet<string>();
						rejected[joinTarget] = value;
					}
					value.Add(sentPassword);
					SavedServer savedServer = ServerStore.Find(joinTarget);
					bool flag = savedServer != null && savedServer.ServerPass == sentPassword;
					pendingPrompt = new Rejection(joinTarget, joinName, flag);
					Logger.LogInfo(JoinAddress.Label(joinTarget, joinName) + " rejected the " + (flag ? "saved " : "") + "password.");
					sentPassword = null;
				}
			}
		}

		[HarmonyPatch(typeof(FejdStartup), "ShowConnectError")]
		internal static class PromptAfterRejection
		{
			[HarmonyPostfix]
			private static void Postfix(FejdStartup __instance)
			{
				if (PasswordFlow.pendingPrompt != null)
				{
					Rejection pendingPrompt = PasswordFlow.pendingPrompt;
					PasswordFlow.pendingPrompt = null;
					((MonoBehaviour)__instance).StartCoroutine(PromptForPassword(__instance, pendingPrompt));
				}
			}
		}

		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static PopupButtonCallback <>9__16_0;

			public static ValidateTextEntry <>9__16_1;

			internal void <PromptForPassword>b__16_0()
			{
				ClosePrompt();
			}

			internal bool <PromptForPassword>b__16_1(string entry)
			{
				return !string.IsNullOrEmpty(entry);
			}
		}

		private static ServerJoinData joinTarget = ServerJoinData.None;

		private static string joinName;

		private static string sentPassword;

		private static ServerJoinData retryTarget = ServerJoinData.None;

		private static string retryPassword;

		private static Rejection pendingPrompt;

		private static readonly Dictionary<ServerJoinData, HashSet<string>> rejected = new Dictionary<ServerJoinData, HashSet<string>>();

		private static ContentType? unmaskedContentType;

		private static IEnumerator PromptForPassword(FejdStartup startup, Rejection rejection)
		{
			yield return null;
			if ((Object)(object)startup == (Object)null || !UnifiedPopup.IsAvailable())
			{
				yield break;
			}
			startup.m_connectionFailedPanel.SetActive(false);
			string text = JoinAddress.Label(rejection.Server, rejection.Name);
			string text2 = (rejection.WasSaved ? ("The saved password for " + text + " is incorrect.\nEnter the current password to reconnect.") : ("The password for " + text + " is incorrect.\nEnter it again to reconnect."));
			object obj = <>c.<>9__16_0;
			if (obj == null)
			{
				PopupButtonCallback val = delegate
				{
					ClosePrompt();
				};
				<>c.<>9__16_0 = val;
				obj = (object)val;
			}
			object obj2 = <>c.<>9__16_1;
			if (obj2 == null)
			{
				ValidateTextEntry val2 = (string entry) => !string.IsNullOrEmpty(entry);
				<>c.<>9__16_1 = val2;
				obj2 = (object)val2;
			}
			UnifiedPopup.Push((PopupBase)new TextEntryPopup("Incorrect password", text2, "Password", (PopupButtonCallback)obj, (ValidateTextEntry)obj2, (RetrieveTextEntryResult)delegate(string entry)
			{
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				if (!string.IsNullOrEmpty(entry))
				{
					ClosePrompt();
					Reconnect(startup, rejection.Server, entry);
				}
			}, false));
			SetPromptMasked(masked: true);
			UnifiedPopup.SetFocus();
		}

		private static void ClosePrompt()
		{
			SetPromptMasked(masked: false);
			UnifiedPopup.Pop();
		}

		private static void SetPromptMasked(bool masked)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)UnifiedPopup.instance == (Object)null)
			{
				return;
			}
			GuiInputField textEntryField = UnifiedPopup.instance.textEntryField;
			if (!((Object)(object)textEntryField == (Object)null))
			{
				if (masked)
				{
					unmaskedContentType = ((TMP_InputField)textEntryField).contentType;
					((TMP_InputField)textEntryField).contentType = (ContentType)7;
				}
				else if (unmaskedContentType.HasValue)
				{
					((TMP_InputField)textEntryField).contentType = unmaskedContentType.Value;
					unmaskedContentType = null;
				}
				((TMP_InputField)textEntryField).ForceLabelUpdate();
			}
		}

		private static void Reconnect(FejdStartup startup, ServerJoinData server, string password)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			retryTarget = server;
			retryPassword = password;
			if (!((Object)(object)startup == (Object)null))
			{
				List<PlayerProfile> profiles = startup.m_profiles;
				int profileIndex = startup.m_profileIndex;
				if (profiles != null && profileIndex >= 0 && profileIndex < profiles.Count)
				{
					PlayerProfile val = profiles[profileIndex];
					startup.SelectCharacter(val.GetFilename(), val.m_fileSource);
					startup.SetServerToJoin(server);
					startup.JoinServer();
				}
				else
				{
					startup.ProceedJoinRequest(server);
				}
			}
		}

		private static string TakeRetryPassword()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			if (!((ServerJoinData)(ref retryTarget)).IsValid || retryTarget != joinTarget)
			{
				return null;
			}
			string result = retryPassword;
			retryTarget = ServerJoinData.None;
			retryPassword = null;
			return result;
		}

		private static string SavedPassword()
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if (FejdStartup.ServerPassword != null)
			{
				return null;
			}
			SavedServer savedServer = ServerStore.Find(joinTarget);
			if (savedServer == null || string.IsNullOrEmpty(savedServer.ServerPass))
			{
				return null;
			}
			if (rejected.TryGetValue(joinTarget, out var value) && value.Contains(savedServer.ServerPass))
			{
				Logger.LogInfo("Not sending the saved password for " + savedServer.Name + "; it was rejected earlier this session.");
				return null;
			}
			Logger.LogDebug("Sending the saved password for " + savedServer.Name + ".");
			return savedServer.ServerPass;
		}

		private static string NameOf(ServerJoinData server)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if (!((ServerJoinData)(ref server)).IsValid)
			{
				return null;
			}
			SavedServer savedServer = ServerStore.Find(server);
			if (savedServer != null && savedServer.HasOwnName)
			{
				return savedServer.Name;
			}
			string result = default(string);
			if (!MultiBackendMatchmaking.TryGetServerName(server, ref result))
			{
				return null;
			}
			return result;
		}
	}
}
namespace AutoConnector.Common
{
	internal static class JoinAddress
	{
		private const string SteamPrefix = "steam:";

		private const string PlayFabPrefix = "playfab:";

		internal static bool TryParse(string address, out ServerJoinData server)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: 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_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			server = ServerJoinData.None;
			if (string.IsNullOrWhiteSpace(address))
			{
				return false;
			}
			address = address.Trim();
			if (address.StartsWith("steam:", StringComparison.OrdinalIgnoreCase))
			{
				if (!ulong.TryParse(address.Substring("steam:".Length).Trim(), out var result))
				{
					return false;
				}
				server = new ServerJoinData(new ServerJoinDataSteamUser(result));
				return ((ServerJoinData)(ref server)).IsValid;
			}
			if (address.StartsWith("playfab:", StringComparison.OrdinalIgnoreCase))
			{
				string text = address.Substring("playfab:".Length).Trim();
				if (text.Length == 0)
				{
					return false;
				}
				server = new ServerJoinData(new ServerJoinDataPlayFabUser(text));
				return true;
			}
			ServerJoinDataDedicated val = default(ServerJoinDataDedicated);
			((ServerJoinDataDedicated)(ref val))..ctor(address);
			if (string.IsNullOrEmpty(((ServerJoinDataDedicated)(ref val)).m_host))
			{
				return false;
			}
			server = new ServerJoinData(val);
			return true;
		}

		internal static string Label(ServerJoinData server, string name)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			if (!string.IsNullOrEmpty(name))
			{
				return name;
			}
			return Format(server);
		}

		internal static string Format(ServerJoinData server)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected I4, but got Unknown
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			ServerJoinDataType type = server.m_type;
			switch (type - 1)
			{
			case 2:
				return ((object)((ServerJoinData)(ref server)).Dedicated/*cast due to .constrained prefix*/).ToString();
			case 0:
			{
				ulong steamID = ((ServerJoinData)(ref server)).SteamUser.m_joinUserID.m_SteamID;
				return "steam:" + steamID;
			}
			case 1:
				return "playfab:" + ((ServerJoinData)(ref server)).PlayFabUser.m_remotePlayerId;
			default:
				return null;
			}
		}
	}
	public class SavedServer
	{
		public string ServerAddress;

		public List<string> ServerAliases;

		public string ServerPass;

		[YamlIgnore]
		internal string Name;

		[YamlIgnore]
		internal ServerJoinData JoinData;

		[YamlIgnore]
		internal List<ServerJoinData> AliasJoinData = new List<ServerJoinData>();

		internal bool HasOwnName
		{
			get
			{
				if (!string.IsNullOrEmpty(Name))
				{
					return Name != ServerAddress;
				}
				return false;
			}
		}

		internal bool Matches(ServerJoinData server)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if (((ServerJoinData)(ref JoinData)).IsValid && JoinData == server)
			{
				return true;
			}
			foreach (ServerJoinData aliasJoinDatum in AliasJoinData)
			{
				if (aliasJoinDatum == server)
				{
					return true;
				}
			}
			return false;
		}
	}
	internal static class ServerStore
	{
		private const string Header = "# AutoConnector saved servers\n#\n# Every server in this list is added to the Favorites tab of the Join Game screen, and its password is\n# entered for you when you join it. Join a server that is not listed here and type its password, and it\n# is added automatically. If a saved password stops working you are asked for the new one, and this file\n# is updated once it is accepted.\n#\n# Each server is filed under its name, which is also the name shown in the server list:\n#\n# Home server:\n#   ServerAddress: 192.168.1.20:2456\n#   ServerAliases:\n#   - valheim.example.com:2456\n#   ServerPass: hunter2\n#\n#   ServerAddress  The address added to favorites, e.g. 192.168.1.20:2456 or valheim.example.com:2456.\n#                  The port is 2456 when left off. Games hosted by a player rather than a dedicated\n#                  server are saved as steam:<id> or playfab:<id>.\n#   ServerAliases  Other addresses for the same server. Optional. The game treats a server added by name\n#                  and the same server joined by IP as two different servers; list the other one here and\n#                  the password is sent to both. Only ServerAddress is added to favorites.\n#   ServerPass     The server's password.\n#\n# If a name or password contains a # or : or starts with a symbol, wrap it in single quotes, and write\n# any single quote inside it twice: 'it''s#secret'\n#\n# Removing a server from favorites in game does not remove it from this file, so it comes back the next\n# time the server list opens. Delete its entry here instead.\n#\n# Passwords are stored as plain text. Anyone who can read this file can read them.\n#\n# AutoConnector rewrites this file when it saves a password, so comments other than this header are lost.\n\n";

		private static readonly ISerializer serializer = ((BuilderSkeleton<SerializerBuilder>)new SerializerBuilder()).WithNamingConvention(PascalCaseNamingConvention.Instance).ConfigureDefaultValuesHandling((DefaultValuesHandling)1).WithQuotingNecessaryStrings(false)
			.DisableAliases()
			.Build();

		private static readonly IDeserializer deserializer = new DeserializerBuilder().WithCaseInsensitivePropertyMatching().IgnoreUnmatchedProperties().Build();

		private static string filePath;

		private static Dictionary<string, SavedServer> current = new Dictionary<string, SavedServer>();

		private static DateTime loadedWriteTimeUtc;

		private static bool fileIsBroken;

		internal static IEnumerable<SavedServer> Servers
		{
			get
			{
				Refresh();
				return current.Values;
			}
		}

		internal static void Init()
		{
			filePath = Path.Combine(Paths.ConfigPath, ValConfig.cfgFolder, "servers.yaml");
			if (!File.Exists(filePath))
			{
				Write();
			}
			Refresh();
		}

		internal static SavedServer Find(ServerJoinData server)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			if (!((ServerJoinData)(ref server)).IsValid)
			{
				return null;
			}
			foreach (SavedServer server2 in Servers)
			{
				if (server2.Matches(server))
				{
					return server2;
				}
			}
			return null;
		}

		internal static void Remember(ServerJoinData server, string name, string password)
		{
			//IL_0012: 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_0093: 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_00b3: Unknown result type (might be due to invalid IL or missing references)
			if (!((ServerJoinData)(ref server)).IsValid || string.IsNullOrEmpty(password))
			{
				return;
			}
			SavedServer savedServer = Find(server);
			if (fileIsBroken)
			{
				Logger.LogWarning("The password for " + JoinAddress.Label(server, name) + " was not saved, because " + filePath + " could not be read. Fix the file and join again to save it.");
				return;
			}
			if (savedServer != null)
			{
				if (savedServer.ServerPass == password)
				{
					return;
				}
				savedServer.ServerPass = password;
				Logger.LogInfo("Updated the saved password for " + savedServer.Name + ".");
			}
			else
			{
				string text = JoinAddress.Format(server);
				if (text == null)
				{
					return;
				}
				savedServer = new SavedServer
				{
					ServerAddress = text,
					ServerPass = password,
					JoinData = server
				};
				savedServer.Name = UnusedName(string.IsNullOrEmpty(name) ? text : name, text);
				current.Add(savedServer.Name, savedServer);
				Logger.LogInfo("Saved " + savedServer.Name + " and its password to " + filePath + ".");
			}
			Write();
		}

		private static string UnusedName(string name, string address)
		{
			if (!current.ContainsKey(name))
			{
				return name;
			}
			string text = name + " (" + address + ")";
			string text2 = text;
			int num = 2;
			while (current.ContainsKey(text2))
			{
				text2 = $"{text} {num}";
				num++;
			}
			return text2;
		}

		private static void Refresh()
		{
			//IL_00b2: Expected O, but got Unknown
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			if (!File.Exists(filePath))
			{
				if (loadedWriteTimeUtc != default(DateTime) || fileIsBroken)
				{
					current = new Dictionary<string, SavedServer>();
					loadedWriteTimeUtc = default(DateTime);
					fileIsBroken = false;
				}
				return;
			}
			DateTime lastWriteTimeUtc = File.GetLastWriteTimeUtc(filePath);
			if (lastWriteTimeUtc == loadedWriteTimeUtc)
			{
				return;
			}
			string text;
			try
			{
				text = File.ReadAllText(filePath);
			}
			catch (Exception ex)
			{
				fileIsBroken = true;
				Logger.LogWarning(filePath + " could not be opened: " + ex.Message);
				return;
			}
			loadedWriteTimeUtc = lastWriteTimeUtc;
			Dictionary<string, SavedServer> dictionary;
			try
			{
				dictionary = deserializer.Deserialize<Dictionary<string, SavedServer>>(text) ?? new Dictionary<string, SavedServer>();
			}
			catch (YamlException ex2)
			{
				YamlException ex3 = ex2;
				fileIsBroken = true;
				string arg = ((((Exception)(object)ex3).InnerException != null) ? ((Exception)(object)ex3).InnerException.Message : ((Exception)(object)ex3).Message);
				string arg2 = filePath;
				Mark start = ex3.Start;
				Logger.LogError($"{arg2} could not be read (line {((Mark)(ref start)).Line}: {arg}). The servers that last loaded from it are still used, but nothing new will be saved to it until it is fixed.");
				return;
			}
			foreach (string item in new List<string>(dictionary.Keys))
			{
				if (dictionary[item] == null)
				{
					dictionary[item] = new SavedServer();
				}
			}
			foreach (KeyValuePair<string, SavedServer> item2 in dictionary)
			{
				ParseAddresses(item2.Key, item2.Value);
			}
			current = dictionary;
			fileIsBroken = false;
			Logger.LogDebug($"Loaded {current.Count} saved servers from {filePath}.");
		}

		private static void ParseAddresses(string name, SavedServer saved)
		{
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			saved.Name = name;
			if (string.IsNullOrWhiteSpace(saved.ServerAddress))
			{
				Logger.LogWarning("Skipping '" + name + "' in " + filePath + ": it has no ServerAddress.");
			}
			else if (!JoinAddress.TryParse(saved.ServerAddress, out saved.JoinData))
			{
				Logger.LogWarning("Skipping '" + name + "' in " + filePath + ": '" + saved.ServerAddress + "' is not an address AutoConnector can read.");
			}
			if (saved.ServerAliases == null)
			{
				return;
			}
			foreach (string serverAlias in saved.ServerAliases)
			{
				if (JoinAddress.TryParse(serverAlias, out var server))
				{
					saved.AliasJoinData.Add(server);
					continue;
				}
				Logger.LogWarning("Ignoring the alias '" + serverAlias + "' of '" + name + "' in " + filePath + ": it is not an address AutoConnector can read.");
			}
		}

		private static void Write()
		{
			try
			{
				Directory.CreateDirectory(Path.GetDirectoryName(filePath));
				File.WriteAllText(filePath, "# AutoConnector saved servers\n#\n# Every server in this list is added to the Favorites tab of the Join Game screen, and its password is\n# entered for you when you join it. Join a server that is not listed here and type its password, and it\n# is added automatically. If a saved password stops working you are asked for the new one, and this file\n# is updated once it is accepted.\n#\n# Each server is filed under its name, which is also the name shown in the server list:\n#\n# Home server:\n#   ServerAddress: 192.168.1.20:2456\n#   ServerAliases:\n#   - valheim.example.com:2456\n#   ServerPass: hunter2\n#\n#   ServerAddress  The address added to favorites, e.g. 192.168.1.20:2456 or valheim.example.com:2456.\n#                  The port is 2456 when left off. Games hosted by a player rather than a dedicated\n#                  server are saved as steam:<id> or playfab:<id>.\n#   ServerAliases  Other addresses for the same server. Optional. The game treats a server added by name\n#                  and the same server joined by IP as two different servers; list the other one here and\n#                  the password is sent to both. Only ServerAddress is added to favorites.\n#   ServerPass     The server's password.\n#\n# If a name or password contains a # or : or starts with a symbol, wrap it in single quotes, and write\n# any single quote inside it twice: 'it''s#secret'\n#\n# Removing a server from favorites in game does not remove it from this file, so it comes back the next\n# time the server list opens. Delete its entry here instead.\n#\n# Passwords are stored as plain text. Anyone who can read this file can read them.\n#\n# AutoConnector rewrites this file when it saves a password, so comments other than this header are lost.\n\n" + serializer.Serialize((object)current));
				loadedWriteTimeUtc = File.GetLastWriteTimeUtc(filePath);
			}
			catch (Exception ex)
			{
				Logger.LogError("Could not write " + filePath + ": " + ex.Message);
			}
		}
	}
}