Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Continue v1.0.0
BepInEx/plugins/Continue/Continue.dll
Decompiled 2 weeks agousing 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) { } } }