Decompiled source of Continue v1.0.0

BepInEx/plugins/Continue/Continue.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_guiutils")]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: IgnoresAccessChecksTo("SoftReferenceableAssets")]
[assembly: IgnoresAccessChecksTo("Splatform")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("minortom")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Main-menu Continue button for the last Valheim character and world or server.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Continue")]
[assembly: AssemblyTitle("Continue")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 minortom.Continue
{
	[HarmonyPatch(typeof(FejdStartup), "SetupGui")]
	internal static class SetupGuiPatch
	{
		private static void Postfix(FejdStartup __instance)
		{
			ContinueButton.TryAdd(__instance);
		}
	}
	[HarmonyPatch(typeof(FejdStartup), "OnWorldStart")]
	internal static class OnWorldStartPatch
	{
		private static void Prefix(FejdStartup __instance)
		{
			SessionRecorder.RecordLocalWorld(__instance);
		}
	}
	[HarmonyPatch(typeof(FejdStartup), "JoinServer")]
	internal static class JoinServerPatch
	{
		private static void Prefix(FejdStartup __instance)
		{
			SessionRecorder.RecordServerJoin(__instance);
		}
	}
	[BepInPlugin("minortom.Continue", "Continue", "1.0.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "minortom.Continue";

		public const string PluginName = "Continue";

		public const string PluginVersion = "1.0.0";

		private Harmony _harmony;

		internal static Plugin Instance { get; private set; }

		internal static ManualLogSource Log { get; private set; }

		internal static ConfigEntry<string> ButtonLabel { get; private set; }

		private void Awake()
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			ButtonLabel = ((BaseUnityPlugin)this).Config.Bind<string>("General", "ButtonLabel", "Continue", "Text shown on the main-menu Continue button.");
			_harmony = new Harmony("minortom.Continue");
			_harmony.PatchAll(typeof(Plugin).Assembly);
			Log.LogInfo((object)"Continue 1.0.0 loaded.");
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}
	}
	internal enum SessionKind
	{
		LocalWorld,
		Server
	}
	internal enum ServerKind
	{
		None,
		Dedicated,
		SteamUser,
		PlayFab
	}
	internal sealed class LastSession : IEquatable<LastSession>
	{
		public SessionKind Kind { get; }

		public string CharacterFile { get; }

		public string CharacterSource { get; }

		public string WorldName { get; }

		public string WorldSource { get; }

		public ServerKind ServerKind { get; }

		public string ServerAddress { get; }

		public string JoinCode { get; }

		public string DisplayName { get; }

		public bool OpenServer { get; }

		public bool PublicServer { get; }

		public bool Crossplay { get; }

		public bool IsComplete
		{
			get
			{
				if (string.IsNullOrEmpty(CharacterFile) || string.IsNullOrEmpty(CharacterSource))
				{
					return false;
				}
				if (Kind == SessionKind.LocalWorld)
				{
					if (!string.IsNullOrEmpty(WorldName))
					{
						return !string.IsNullOrEmpty(WorldSource);
					}
					return false;
				}
				if (ServerKind != ServerKind.None)
				{
					return !string.IsNullOrEmpty(ServerAddress);
				}
				return false;
			}
		}

		private LastSession(SessionKind kind, string characterFile, string characterSource, string worldName, string worldSource, ServerKind serverKind, string serverAddress, string joinCode, string displayName, bool openServer, bool publicServer, bool crossplay)
		{
			Kind = kind;
			CharacterFile = characterFile ?? string.Empty;
			CharacterSource = characterSource ?? string.Empty;
			WorldName = worldName ?? string.Empty;
			WorldSource = worldSource ?? string.Empty;
			ServerKind = serverKind;
			ServerAddress = serverAddress ?? string.Empty;
			JoinCode = joinCode ?? string.Empty;
			DisplayName = displayName ?? string.Empty;
			OpenServer = openServer;
			PublicServer = publicServer;
			Crossplay = crossplay;
		}

		public static LastSession LocalWorld(string characterFile, string characterSource, string worldName, string worldSource, bool openServer, bool publicServer, bool crossplay)
		{
			return new LastSession(SessionKind.LocalWorld, characterFile, characterSource, worldName, worldSource, ServerKind.None, string.Empty, string.Empty, worldName, openServer, publicServer, crossplay);
		}

		public static LastSession Server(string characterFile, string characterSource, ServerKind serverKind, string serverAddress, string joinCode, string displayName)
		{
			return new LastSession(SessionKind.Server, characterFile, characterSource, string.Empty, string.Empty, serverKind, serverAddress, joinCode, string.IsNullOrEmpty(displayName) ? serverAddress : displayName, openServer: false, publicServer: false, crossplay: false);
		}

		public bool Equals(LastSession other)
		{
			if (other == null)
			{
				return false;
			}
			if (Kind == other.Kind && CharacterFile == other.CharacterFile && CharacterSource == other.CharacterSource && WorldName == other.WorldName && WorldSource == other.WorldSource && ServerKind == other.ServerKind && ServerAddress == other.ServerAddress && JoinCode == other.JoinCode && DisplayName == other.DisplayName && OpenServer == other.OpenServer && PublicServer == other.PublicServer)
			{
				return Crossplay == other.Crossplay;
			}
			return false;
		}

		public override bool Equals(object obj)
		{
			return Equals(obj as LastSession);
		}

		public override int GetHashCode()
		{
			return ((((((int)Kind * 397) ^ CharacterFile.GetHashCode()) * 397) ^ WorldName.GetHashCode()) * 397) ^ ServerAddress.GetHashCode();
		}

		public override string ToString()
		{
			return $"{Kind} '{DisplayName}' as {CharacterFile}";
		}
	}
	internal static class LastSessionFormat
	{
		private const string Version = "2";

		private const char Separator = '|';

		private const char Escape = '\\';

		private const int FieldCount = 13;

		public static string Write(LastSession session)
		{
			if (session == null)
			{
				throw new ArgumentNullException("session");
			}
			string[] array = new string[13]
			{
				"2",
				session.Kind.ToString(),
				session.CharacterFile,
				session.CharacterSource,
				session.WorldName,
				session.WorldSource,
				session.ServerKind.ToString(),
				session.ServerAddress,
				session.JoinCode,
				session.DisplayName,
				session.OpenServer ? "1" : "0",
				session.PublicServer ? "1" : "0",
				session.Crossplay ? "1" : "0"
			};
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < array.Length; i++)
			{
				if (i > 0)
				{
					stringBuilder.Append('|');
				}
				string text = array[i];
				foreach (char c in text)
				{
					if ((c == '\\' || c == '|') ? true : false)
					{
						stringBuilder.Append('\\');
					}
					stringBuilder.Append(c);
				}
			}
			return stringBuilder.ToString();
		}

		public static LastSession Read(string text)
		{
			if (string.IsNullOrEmpty(text))
			{
				return null;
			}
			List<string> list = Split(text);
			if (list == null || list.Count != 13 || list[0] != "2")
			{
				return null;
			}
			if (!TryParseEnum<SessionKind>(list[1], out var value))
			{
				return null;
			}
			if (!TryParseEnum<ServerKind>(list[6], out var value2))
			{
				return null;
			}
			bool openServer = list[10] == "1";
			bool publicServer = list[11] == "1";
			bool crossplay = list[12] == "1";
			LastSession lastSession = ((value == SessionKind.LocalWorld) ? LastSession.LocalWorld(list[2], list[3], list[4], list[5], openServer, publicServer, crossplay) : LastSession.Server(list[2], list[3], value2, list[7], list[8], list[9]));
			if (!lastSession.IsComplete)
			{
				return null;
			}
			return lastSession;
		}

		private static bool TryParseEnum<T>(string text, out T value) where T : struct
		{
			value = default(T);
			if (string.IsNullOrEmpty(text))
			{
				return false;
			}
			if (Array.IndexOf(Enum.GetNames(typeof(T)), text) < 0)
			{
				return false;
			}
			return Enum.TryParse<T>(text, ignoreCase: false, out value);
		}

		private static List<string> Split(string text)
		{
			List<string> list = new List<string>();
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = 0; i < text.Length; i++)
			{
				char c = text[i];
				switch (c)
				{
				case '\\':
					if (i + 1 >= text.Length)
					{
						return null;
					}
					stringBuilder.Append(text[++i]);
					break;
				case '|':
					list.Add(stringBuilder.ToString());
					stringBuilder.Clear();
					break;
				default:
					stringBuilder.Append(c);
					break;
				}
			}
			list.Add(stringBuilder.ToString());
			return list;
		}
	}
	internal static class SessionRecorder
	{
		public static void RecordLocalWorld(FejdStartup startup)
		{
			try
			{
				PlayerProfile selectedProfile = GetSelectedProfile(startup);
				World world = startup.m_world;
				if (selectedProfile != null && world != null)
				{
					bool openServer = IsOn(startup.m_openServerToggle);
					bool publicServer = IsOn(startup.m_publicServerToggle);
					bool crossplay = IsOn(startup.m_crossplayServerToggle);
					SessionStore.Save(LastSession.LocalWorld(selectedProfile.GetFilename(), ((object)Unsafe.As<FileSource, FileSource>(ref selectedProfile.m_fileSource)/*cast due to .constrained prefix*/).ToString(), world.m_name, ((object)Unsafe.As<FileSource, FileSource>(ref world.m_fileSource)/*cast due to .constrained prefix*/).ToString(), openServer, publicServer, crossplay));
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("Failed to record local session: " + ex.Message));
				}
			}
		}

		public static void RecordServerJoin(FejdStartup startup)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!startup.HasServerToJoin())
				{
					return;
				}
				PlayerProfile selectedProfile = GetSelectedProfile(startup);
				if (selectedProfile != null)
				{
					ServerJoinData serverToJoin = startup.GetServerToJoin();
					if (((ServerJoinData)(ref serverToJoin)).IsValid && TryDescribeServer(serverToJoin, out var kind, out var address, out var joinCode, out var displayName))
					{
						SessionStore.Save(LastSession.Server(selectedProfile.GetFilename(), ((object)Unsafe.As<FileSource, FileSource>(ref selectedProfile.m_fileSource)/*cast due to .constrained prefix*/).ToString(), kind, address, joinCode, displayName));
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("Failed to record multiplayer session: " + ex.Message));
				}
			}
		}

		private static PlayerProfile GetSelectedProfile(FejdStartup startup)
		{
			if (startup.m_profiles != null && startup.m_profileIndex >= 0 && startup.m_profileIndex < startup.m_profiles.Count)
			{
				return startup.m_profiles[startup.m_profileIndex];
			}
			string filename = PlatformPrefs.GetString("profile", string.Empty);
			if (string.IsNullOrEmpty(filename))
			{
				return null;
			}
			return SaveSystem.GetAllPlayerProfiles().Find((PlayerProfile p) => p.GetFilename() == filename);
		}

		private static bool IsOn(Toggle toggle)
		{
			if ((Object)(object)toggle != (Object)null)
			{
				return toggle.isOn;
			}
			return false;
		}

		private static bool TryDescribeServer(ServerJoinData data, out ServerKind kind, out string address, out string joinCode, out string displayName)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//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_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Expected I4, but got Unknown
			//IL_0058: 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_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: 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)
			kind = ServerKind.None;
			address = string.Empty;
			joinCode = string.Empty;
			displayName = string.Empty;
			ServerJoinDataType type = data.m_type;
			switch (type - 1)
			{
			case 2:
				kind = ServerKind.Dedicated;
				address = ((object)((ServerJoinData)(ref data)).Dedicated/*cast due to .constrained prefix*/).ToString();
				break;
			case 0:
			{
				kind = ServerKind.SteamUser;
				ulong steamID = ((ServerJoinData)(ref data)).SteamUser.m_joinUserID.m_SteamID;
				address = steamID.ToString(CultureInfo.InvariantCulture);
				break;
			}
			case 1:
				kind = ServerKind.PlayFab;
				address = ((ServerJoinData)(ref data)).PlayFabUser.m_remotePlayerId;
				joinCode = MultiBackendMatchmaking.GetServerMatchmakingData(data, default(DateTime)).m_joinCode ?? string.Empty;
				break;
			default:
				return false;
			}
			displayName = MultiBackendMatchmaking.GetServerName(data);
			if (string.IsNullOrWhiteSpace(displayName))
			{
				displayName = address;
			}
			return !string.IsNullOrEmpty(address);
		}
	}
	internal static class SessionStore
	{
		private const string Key = "minortom.Continue.LastSession";

		public static LastSession Load()
		{
			LastSession lastSession = LastSessionFormat.Read(PlatformPrefs.GetString("minortom.Continue.LastSession", string.Empty));
			if (lastSession != null)
			{
				return lastSession;
			}
			return FromVanillaPrefs();
		}

		public static void Save(LastSession session)
		{
			if (session != null && session.IsComplete)
			{
				PlatformPrefs.SetString("minortom.Continue.LastSession", LastSessionFormat.Write(session));
				PlatformPrefs.Save();
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)$"Recorded session {session}.");
				}
			}
		}

		public static bool HasAnySession()
		{
			return Load() != null;
		}

		private static LastSession FromVanillaPrefs()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			string text = PlatformPrefs.GetString("profile", string.Empty);
			string text2 = PlatformPrefs.GetString("world", string.Empty);
			if (string.IsNullOrEmpty(text) || string.IsNullOrEmpty(text2))
			{
				return null;
			}
			string text3 = ((object)(FileSource)2/*cast due to .constrained prefix*/).ToString();
			return LastSession.LocalWorld(text, text3, text2, text3, openServer: false, publicServer: false, crossplay: false);
		}
	}
	internal static class ContinueButton
	{
		private const string ButtonName = "minortom_Continue";

		private const string SubtitleName = "minortom_ContinueSubtitle";

		public static void TryAdd(FejdStartup menu)
		{
			try
			{
				Add(menu);
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("Could not add Continue button: " + ex.Message));
				}
			}
		}

		private static void Add(FejdStartup menu)
		{
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Expected O, but got Unknown
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c1: Expected O, but got Unknown
			//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			//IL_0274: Unknown result type (might be due to invalid IL or missing references)
			GameObject menuList = menu.m_menuList;
			if ((Object)(object)menuList == (Object)null)
			{
				return;
			}
			Button[] componentsInChildren = menuList.GetComponentsInChildren<Button>(true);
			Button[] array = componentsInChildren;
			for (int i = 0; i < array.Length; i++)
			{
				if (((Object)array[i]).name == "minortom_Continue")
				{
					return;
				}
			}
			LastSession lastSession = SessionStore.Load();
			if (lastSession == null)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)"No previous session; Continue button hidden.");
				}
				return;
			}
			Button val = FindStartGameButton(componentsInChildren);
			if ((Object)(object)val == (Object)null)
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)"Could not find Start game button; Continue not added.");
				}
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, ((Component)val).transform.parent);
			try
			{
				((Object)val2).name = "minortom_Continue";
				val2.transform.SetSiblingIndex(((Component)val).transform.GetSiblingIndex());
				Localize[] componentsInChildren2 = val2.GetComponentsInChildren<Localize>(true);
				for (int i = 0; i < componentsInChildren2.Length; i++)
				{
					Object.DestroyImmediate((Object)(object)componentsInChildren2[i]);
				}
				TMP_Text[] componentsInChildren3 = val2.GetComponentsInChildren<TMP_Text>(true);
				TMP_Text styleSource = ((componentsInChildren3.Length != 0) ? componentsInChildren3[0] : null);
				string text = Plugin.ButtonLabel?.Value ?? "Continue";
				TMP_Text[] array2 = componentsInChildren3;
				foreach (TMP_Text obj in array2)
				{
					obj.text = text;
					obj.alignment = (TextAlignmentOptions)514;
					obj.horizontalAlignment = (HorizontalAlignmentOptions)2;
					obj.verticalAlignment = (VerticalAlignmentOptions)512;
					obj.margin = Vector4.zero;
					obj.textWrappingMode = (TextWrappingModes)0;
				}
				Button button = val2.GetComponent<Button>();
				button.onClick = new ButtonClickedEvent();
				((UnityEvent)button.onClick).AddListener((UnityAction)delegate
				{
					LastSession session = SessionStore.Load();
					ContinueLauncher.Resume(menu, session, button);
				});
				if ((Object)(object)((Component)((Component)val).transform.parent).GetComponent<LayoutGroup>() == (Object)null)
				{
					RectTransform component = ((Component)val).GetComponent<RectTransform>();
					RectTransform component2 = ((Component)button).GetComponent<RectTransform>();
					float num = EstimateVerticalStep(componentsInChildren, val, component);
					component2.anchoredPosition = component.anchoredPosition + new Vector2(0f, num + 22f);
				}
				AddSubtitle(val2, styleSource, lastSession);
				menu.m_menuButtons = menuList.GetComponentsInChildren<Button>();
				WireNavigation(button, val);
				if ((Object)(object)menu.m_merchStoreButton != (Object)null)
				{
					((Selectable)button).navigation = WithRight(((Selectable)button).navigation, (Selectable)(object)menu.m_merchStoreButton);
				}
				ManualLogSource log3 = Plugin.Log;
				if (log3 != null)
				{
					log3.LogInfo((object)$"Continue button added for {lastSession}.");
				}
			}
			catch
			{
				Object.Destroy((Object)(object)val2);
				throw;
			}
		}

		private static void AddSubtitle(GameObject continueButton, TMP_Text styleSource, LastSession session)
		{
			//IL_0166: 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_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: 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_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)styleSource == (Object)null || (Object)(object)styleSource.font == (Object)null)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"Continue subtitle skipped; menu font was unavailable.");
				}
				return;
			}
			string text = ResolveCharacterName(session);
			string text2 = ((!string.IsNullOrWhiteSpace(session.DisplayName)) ? session.DisplayName : ((session.Kind == SessionKind.LocalWorld) ? session.WorldName : session.ServerAddress));
			string text3 = Truncate(text + " — " + text2, 48);
			GameObject val = Object.Instantiate<GameObject>(((Component)styleSource).gameObject, continueButton.transform.parent);
			val.SetActive(false);
			((Object)val).name = "minortom_ContinueSubtitle";
			Localize[] componentsInChildren = val.GetComponentsInChildren<Localize>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
			}
			Graphic[] componentsInChildren2 = val.GetComponentsInChildren<Graphic>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				componentsInChildren2[i].raycastTarget = false;
			}
			TMP_Text val2 = val.GetComponent<TMP_Text>() ?? val.GetComponentInChildren<TMP_Text>(true);
			if ((Object)(object)val2 == (Object)null)
			{
				Object.Destroy((Object)(object)val);
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogWarning((object)"Continue subtitle skipped; cloned label had no TMP_Text.");
				}
				return;
			}
			val2.font = styleSource.font;
			val2.fontSharedMaterial = styleSource.fontSharedMaterial;
			val2.fontSize = Mathf.Max(12f, styleSource.fontSize * 0.45f);
			((Graphic)val2).color = new Color(1f, 1f, 1f, 0.6f);
			val2.alignment = (TextAlignmentOptions)514;
			val2.horizontalAlignment = (HorizontalAlignmentOptions)2;
			val2.verticalAlignment = (VerticalAlignmentOptions)512;
			val2.margin = Vector4.zero;
			val2.text = text3;
			val2.richText = false;
			((Graphic)val2).raycastTarget = false;
			val2.textWrappingMode = (TextWrappingModes)0;
			val2.overflowMode = (TextOverflowModes)1;
			RectTransform component = continueButton.GetComponent<RectTransform>();
			RectTransform component2 = val.GetComponent<RectTransform>();
			component2.anchorMin = component.anchorMin;
			component2.anchorMax = component.anchorMax;
			component2.pivot = new Vector2(0.5f, 1f);
			Rect rect = component.rect;
			component2.sizeDelta = new Vector2(((Rect)(ref rect)).width, 22f);
			Vector2 anchoredPosition = component.anchoredPosition;
			rect = component.rect;
			component2.anchoredPosition = anchoredPosition - new Vector2(0f, ((Rect)(ref rect)).height * 0.5f + 2f);
			val.transform.SetSiblingIndex(continueButton.transform.GetSiblingIndex() + 1);
			val.SetActive(true);
		}

		private static string ResolveCharacterName(LastSession session)
		{
			PlayerProfile val = ContinueLauncher.FindProfile(SaveSystem.GetAllPlayerProfiles(), session);
			if (val != null)
			{
				string name = val.GetName();
				if (!string.IsNullOrWhiteSpace(name))
				{
					return name;
				}
			}
			if (!string.IsNullOrEmpty(session.CharacterFile))
			{
				return session.CharacterFile;
			}
			return "?";
		}

		private static string Truncate(string text, int maxLength)
		{
			if (string.IsNullOrEmpty(text) || text.Length <= maxLength)
			{
				return text;
			}
			int num = Math.Max(1, maxLength - 1);
			if (char.IsHighSurrogate(text[num - 1]))
			{
				num--;
			}
			return text.Substring(0, num) + "…";
		}

		private static float EstimateVerticalStep(Button[] buttons, Button start, RectTransform startRect)
		{
			//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_0058: Unknown result type (might be due to invalid IL or missing references)
			Rect rect = startRect.rect;
			float result = ((Rect)(ref rect)).height + 8f;
			float num = float.MaxValue;
			foreach (Button val in buttons)
			{
				if (!((Object)(object)((Component)val).transform.parent != (Object)(object)((Component)start).transform.parent))
				{
					float num2 = Mathf.Abs(((Component)val).GetComponent<RectTransform>().anchoredPosition.y - startRect.anchoredPosition.y);
					if (num2 > 1f)
					{
						num = Mathf.Min(num, num2);
					}
				}
			}
			if (!(num < float.MaxValue))
			{
				return result;
			}
			return num;
		}

		private static void WireNavigation(Button continueButton, Button start)
		{
			//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_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: 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)
			Navigation navigation = ((Selectable)continueButton).navigation;
			((Navigation)(ref navigation)).selectOnDown = (Selectable)(object)start;
			((Selectable)continueButton).navigation = navigation;
			Navigation navigation2 = ((Selectable)start).navigation;
			((Navigation)(ref navigation2)).selectOnUp = (Selectable)(object)continueButton;
			((Selectable)start).navigation = navigation2;
		}

		private static Navigation WithRight(Navigation navigation, Selectable right)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			((Navigation)(ref navigation)).selectOnRight = right;
			return navigation;
		}

		private static Button FindStartGameButton(Button[] buttons)
		{
			Button[] array = buttons;
			foreach (Button val in array)
			{
				for (int j = 0; j < ((UnityEventBase)val.onClick).GetPersistentEventCount(); j++)
				{
					if (((UnityEventBase)val.onClick).GetPersistentMethodName(j) == "OnStartGame")
					{
						return val;
					}
				}
			}
			array = buttons;
			foreach (Button val2 in array)
			{
				string name = ((Object)val2).name;
				if ((name == "StartGame" || name == "Start") ? true : false)
				{
					return val2;
				}
			}
			array = buttons;
			foreach (Button val3 in array)
			{
				if (((Component)val3).gameObject.activeInHierarchy)
				{
					return val3;
				}
			}
			return null;
		}
	}
	internal static class ContinueLauncher
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static PopupButtonCallback <>9__9_0;

			internal void <ShowWarning>b__9_0()
			{
				UnifiedPopup.Pop();
			}
		}

		private static Button _busyButton;

		public static PlayerProfile FindProfile(IList<PlayerProfile> profiles, LastSession session)
		{
			if (profiles == null || session == null)
			{
				return null;
			}
			foreach (PlayerProfile profile in profiles)
			{
				if (profile.GetFilename() == session.CharacterFile && ((object)Unsafe.As<FileSource, FileSource>(ref profile.m_fileSource)/*cast due to .constrained prefix*/).ToString() == session.CharacterSource)
				{
					return profile;
				}
			}
			foreach (PlayerProfile profile2 in profiles)
			{
				if (profile2.GetFilename() == session.CharacterFile)
				{
					return profile2;
				}
			}
			return null;
		}

		public static World FindWorld(LastSession session)
		{
			if (session == null)
			{
				return null;
			}
			List<World> worldList = SaveSystem.GetWorldList();
			World val = worldList.Find((World w) => w.m_name == session.WorldName && ((object)Unsafe.As<FileSource, FileSource>(ref w.m_fileSource)/*cast due to .constrained prefix*/).ToString() == session.WorldSource && (int)w.m_dataError == 0);
			if (val != null)
			{
				return val;
			}
			return worldList.Find((World w) => w.m_name == session.WorldName && (int)w.m_dataError == 0);
		}

		public static void Resume(FejdStartup menu, LastSession session, Button button)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			_busyButton = button;
			if ((Object)(object)_busyButton != (Object)null)
			{
				((Selectable)_busyButton).interactable = false;
			}
			try
			{
				if (session == null || !session.IsComplete)
				{
					Fail(menu, "There is nothing to continue yet.");
					return;
				}
				List<PlayerProfile> allPlayerProfiles = SaveSystem.GetAllPlayerProfiles();
				PlayerProfile val = FindProfile(allPlayerProfiles, session);
				if (val == null)
				{
					Fail(menu, "The saved character was not found.");
					return;
				}
				menu.m_profiles = allPlayerProfiles;
				menu.m_profileIndex = allPlayerProfiles.IndexOf(val);
				menu.SelectCharacter(val.GetFilename(), val.m_fileSource);
				if (session.Kind == SessionKind.LocalWorld)
				{
					StartLocalWorld(menu, session);
				}
				else
				{
					JoinServer(menu, session);
				}
			}
			catch (Exception arg)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)$"Continue failed: {arg}");
				}
				Fail(menu, "Could not continue. Start the game normally.");
			}
		}

		private static void StartLocalWorld(FejdStartup menu, LastSession session)
		{
			World val = FindWorld(session);
			if (val == null)
			{
				Fail(menu, "The saved world can no longer be loaded.");
				return;
			}
			menu.m_world = val;
			SetToggle(menu.m_openServerToggle, session.OpenServer);
			SetToggle(menu.m_publicServerToggle, session.PublicServer);
			SetToggle(menu.m_crossplayServerToggle, session.Crossplay);
			if ((Object)(object)menu.m_serverPassword != (Object)null)
			{
				((TMP_InputField)menu.m_serverPassword).text = string.Empty;
			}
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)$"Continuing {session}.");
			}
			menu.OnWorldStart();
			((MonoBehaviour)menu).StartCoroutine(ReenableAfterDelay(_busyButton));
		}

		private static void JoinServer(FejdStartup menu, LastSession session)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Expected O, but got Unknown
			//IL_0147: Expected O, but got Unknown
			switch (session.ServerKind)
			{
			case ServerKind.Dedicated:
				Join(menu, new ServerJoinData(new ServerJoinDataDedicated(session.ServerAddress)), session);
				break;
			case ServerKind.SteamUser:
			{
				if (!ulong.TryParse(session.ServerAddress, NumberStyles.None, CultureInfo.InvariantCulture, out var result))
				{
					Fail(menu, "The saved Steam server id is invalid.");
				}
				else
				{
					Join(menu, new ServerJoinData(new ServerJoinDataSteamUser(result)), session);
				}
				break;
			}
			case ServerKind.PlayFab:
			{
				ServerJoinData byId = new ServerJoinData(new ServerJoinDataPlayFabUser(session.ServerAddress));
				if (session.JoinCode.Length == 0 || !PlayFabManager.IsLoggedIn)
				{
					Join(menu, byId, session);
					break;
				}
				ZPlayFabMatchmaking.ResolveJoinCode(session.JoinCode, (ZPlayFabMatchmakingSuccessCallback)delegate(PlayFabMatchmakingServerData data)
				{
					//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)
					Join(menu, new ServerJoinData(new ServerJoinDataPlayFabUser(data.remotePlayerId)), session);
				}, (ZPlayFabMatchmakingFailedCallback)delegate(ZPLayFabMatchmakingFailReason reason)
				{
					//IL_0020: Unknown result type (might be due to invalid IL or missing references)
					//IL_003c: Unknown result type (might be due to invalid IL or missing references)
					ManualLogSource log = Plugin.Log;
					if (log != null)
					{
						log.LogInfo((object)$"Join code {session.JoinCode} failed ({reason}); trying saved server id.");
					}
					Join(menu, byId, session);
				});
				break;
			}
			default:
				Fail(menu, "Unknown saved server type.");
				break;
			}
		}

		private static void Join(FejdStartup menu, ServerJoinData data, LastSession session)
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			if (menu == null || !menu.m_mainMenu.activeInHierarchy)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogInfo((object)$"{session} resolved after leaving the main menu; not joining.");
				}
				if ((Object)(object)menu != (Object)null)
				{
					((MonoBehaviour)menu).StartCoroutine(ReenableAfterDelay(_busyButton));
				}
			}
			else if (!((ServerJoinData)(ref data)).IsValid)
			{
				Fail(menu, "The saved server address is not usable.");
			}
			else
			{
				ManualLogSource log2 = Plugin.Log;
				if (log2 != null)
				{
					log2.LogInfo((object)$"Continuing {session}.");
				}
				menu.SetServerToJoin(data);
				menu.JoinServer();
				((MonoBehaviour)menu).StartCoroutine(ReenableAfterDelay(_busyButton));
			}
		}

		private static void SetToggle(Toggle toggle, bool value)
		{
			if ((Object)(object)toggle != (Object)null)
			{
				toggle.SetIsOnWithoutNotify(value);
			}
		}

		private static void Fail(FejdStartup menu, string message)
		{
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogWarning((object)("Continue: " + message));
			}
			ShowWarning(message);
			if ((Object)(object)_busyButton != (Object)null)
			{
				((Selectable)_busyButton).interactable = true;
			}
		}

		private static void ShowWarning(string message)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			try
			{
				string obj = Plugin.ButtonLabel?.Value ?? "Continue";
				object obj2 = <>c.<>9__9_0;
				if (obj2 == null)
				{
					PopupButtonCallback val = delegate
					{
						UnifiedPopup.Pop();
					};
					<>c.<>9__9_0 = val;
					obj2 = (object)val;
				}
				UnifiedPopup.Push((PopupBase)new WarningPopup(obj, message, (PopupButtonCallback)obj2, false));
			}
			catch (Exception ex)
			{
				ManualLogSource log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)("Could not show Continue dialog: " + ex.Message));
				}
			}
		}

		private static IEnumerator ReenableAfterDelay(Button button)
		{
			yield return (object)new WaitForSecondsRealtime(3f);
			if ((Object)(object)button != (Object)null)
			{
				((Selectable)button).interactable = true;
			}
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}