Decompiled source of BifrostConnect v1.0.4

BifrostConnect.dll

Decompiled 4 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using BifrostConnect.Models;
using BifrostConnect.UI;
using HarmonyLib;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("Jubaroo")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © 2026 Jubaroo")]
[assembly: AssemblyDescription("Main menu dedicated server browser with auto-fill passwords and scrollable directory for Valheim")]
[assembly: AssemblyFileVersion("1.0.4.0")]
[assembly: AssemblyInformationalVersion("1.0.4")]
[assembly: AssemblyProduct("BifrostConnect")]
[assembly: AssemblyTitle("BifrostConnect")]
[assembly: AssemblyVersion("1.0.4.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[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 BifrostConnect
{
	[BepInPlugin("com.jubaroo.bifrostconnect", "Bifrost Connect", "1.0.4")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string ModGUID = "com.jubaroo.bifrostconnect";

		public const string ModName = "Bifrost Connect";

		public const string ModVersion = "1.0.4";

		private readonly Harmony _harmony = new Harmony("com.jubaroo.bifrostconnect");

		internal static ManualLogSource Log = null;

		public static List<ServerEntry> ServerList = new List<ServerEntry>();

		private static string _jsonConfigPath = null;

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			_jsonConfigPath = Path.Combine(Paths.ConfigPath, "BifrostConnect_Servers.json");
			LoadServerConfig();
			Log.LogInfo((object)"Initializing Bifrost Connect hooks...");
			_harmony.PatchAll();
		}

		private static string StripComments(string text)
		{
			string[] array = text.Split(new string[3] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
			StringBuilder stringBuilder = new StringBuilder();
			string[] array2 = array;
			foreach (string text2 in array2)
			{
				string text3 = text2.Trim();
				if (!text3.StartsWith("//") && !text3.StartsWith("#"))
				{
					stringBuilder.AppendLine(text2);
				}
			}
			return stringBuilder.ToString();
		}

		internal static void LoadServerConfig()
		{
			if (!File.Exists(_jsonConfigPath) || new FileInfo(_jsonConfigPath).Length == 0L)
			{
				Log.LogInfo((object)("Server config not found at '" + _jsonConfigPath + "'. Generating default template with examples."));
				GenerateDefaultConfig();
			}
			try
			{
				string text = File.ReadAllText(_jsonConfigPath);
				ServerList = new List<ServerEntry>();
				try
				{
					ServerListWrapper serverListWrapper = JsonConvert.DeserializeObject<ServerListWrapper>(text);
					if (serverListWrapper != null && serverListWrapper.Servers != null && serverListWrapper.Servers.Count > 0)
					{
						ServerList = serverListWrapper.Servers;
					}
					else
					{
						List<ServerEntry> list = JsonConvert.DeserializeObject<List<ServerEntry>>(text);
						if (list != null && list.Count > 0)
						{
							ServerList = list;
						}
					}
				}
				catch (Exception ex)
				{
					Log.LogWarning((object)("Newtonsoft.Json direct parse attempt: " + ex.Message + ". Trying with stripped comments."));
					try
					{
						ServerListWrapper serverListWrapper2 = JsonConvert.DeserializeObject<ServerListWrapper>(StripComments(text));
						if (serverListWrapper2 != null && serverListWrapper2.Servers != null && serverListWrapper2.Servers.Count > 0)
						{
							ServerList = serverListWrapper2.Servers;
						}
					}
					catch (Exception ex2)
					{
						Log.LogWarning((object)("Stripped JSON parse attempt: " + ex2.Message + ". Proceeding to line-by-line fallback."));
					}
				}
				if (ServerList.Count == 0)
				{
					string[] array = text.Split(new string[3] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
					for (int i = 0; i < array.Length; i++)
					{
						string text2 = array[i].Trim();
						if (string.IsNullOrEmpty(text2) || text2.StartsWith("{") || text2.StartsWith("}") || text2.StartsWith("[") || text2.StartsWith("]") || text2.StartsWith("//") || text2.StartsWith("#"))
						{
							continue;
						}
						string[] array2 = text2.Split(new char[1] { ':' });
						if (array2.Length >= 3)
						{
							string name = array2[0].Trim();
							string iP = array2[1].Trim();
							if (int.TryParse(array2[2].Trim(), out var result))
							{
								string password = ((array2.Length > 3) ? array2[3].Trim() : string.Empty);
								ServerList.Add(new ServerEntry
								{
									Name = name,
									IP = iP,
									Port = result,
									Password = password
								});
							}
						}
					}
				}
				Log.LogInfo((object)$"Loaded {ServerList.Count} servers from config: {_jsonConfigPath}");
				foreach (ServerEntry server in ServerList)
				{
					Log.LogInfo((object)$"  - Server: '{server.Name}' ({server.IP}:{server.Port})");
				}
			}
			catch (Exception ex3)
			{
				Log.LogError((object)("Failed to load server config: " + ex3.Message));
			}
		}

		private static void GenerateDefaultConfig()
		{
			string contents = "// ====================================================================\r\n// BifrostConnect Server Configuration\r\n// ====================================================================\r\n// Add your Valheim dedicated servers to the 'Servers' list below.\r\n//\r\n// Fields:\r\n//   - Name:     The display name shown on the button in the main menu.\r\n//   - IP:       The server IPv4 address or domain (e.g. 192.168.1.50 or valheim.myserver.com).\r\n//   - Port:     The connection port (default Valheim server port is 2456).\r\n//   - Password: The server password (leave as \"\" if password is not required).\r\n//\r\n// You can add as many servers as you like to this list!\r\n// ====================================================================\r\n{\r\n  \"Servers\": [\r\n    {\r\n      \"Name\": \"My Survival Server\",\r\n      \"IP\": \"127.0.0.1\",\r\n      \"Port\": 2456,\r\n      \"Password\": \"\"\r\n    },\r\n    {\r\n      \"Name\": \"Community Dedicated Server\",\r\n      \"IP\": \"192.168.1.100\",\r\n      \"Port\": 2456,\r\n      \"Password\": \"secretpassword\"\r\n    },\r\n    {\r\n      \"Name\": \"Modded World\",\r\n      \"IP\": \"valheim.example.com\",\r\n      \"Port\": 2456,\r\n      \"Password\": \"valheim123\"\r\n    }\r\n  ]\r\n}\r\n";
			File.WriteAllText(_jsonConfigPath, contents);
		}
	}
}
namespace BifrostConnect.UI
{
	public class MenuEscapeHandler : MonoBehaviour
	{
		public FejdStartup? Instance;

		private void Update()
		{
			if (Input.GetKeyDown((KeyCode)27) && (Object)(object)Instance != (Object)null)
			{
				MenuBuilder.HandleEscape(Instance);
			}
		}
	}
	public static class MenuBuilder
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static UnityAction <0>__CloseConfirmation;
		}

		private static GameObject _customMenuPanel;

		private static GameObject _confirmPanel;

		public static void InjectMainMenuButton(FejdStartup instance)
		{
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Expected O, but got Unknown
			if ((Object)(object)instance.m_mainMenu == (Object)null || (Object)(object)Utils.FindChild(instance.m_mainMenu.transform, "Button_BifrostConnect", (IterativeSearchType)0) != (Object)null)
			{
				return;
			}
			Transform val = Utils.FindChild(instance.m_mainMenu.transform, "Settings", (IterativeSearchType)0);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, val.parent);
			((Object)val2).name = "Button_BifrostConnect";
			val2.transform.SetSiblingIndex(val.GetSiblingIndex());
			Localize[] componentsInChildren = val2.GetComponentsInChildren<Localize>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.DestroyImmediate((Object)(object)componentsInChildren[i]);
			}
			TMP_Text[] componentsInChildren2 = val2.GetComponentsInChildren<TMP_Text>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				componentsInChildren2[i].text = "BIFROST CONNECT";
			}
			Text[] componentsInChildren3 = val2.GetComponentsInChildren<Text>(true);
			for (int i = 0; i < componentsInChildren3.Length; i++)
			{
				componentsInChildren3[i].text = "BIFROST CONNECT";
			}
			Button component = val2.GetComponent<Button>();
			if ((Object)(object)component != (Object)null)
			{
				for (int j = 0; j < ((UnityEventBase)component.onClick).GetPersistentEventCount(); j++)
				{
					((UnityEventBase)component.onClick).SetPersistentListenerState(j, (UnityEventCallState)0);
				}
				((UnityEventBase)component.onClick).RemoveAllListeners();
				((UnityEvent)component.onClick).AddListener((UnityAction)delegate
				{
					OpenMenu(instance);
				});
			}
			UIInputHandler[] componentsInChildren4 = val2.GetComponentsInChildren<UIInputHandler>(true);
			foreach (UIInputHandler obj in componentsInChildren4)
			{
				obj.m_onLeftClick = null;
				obj.m_onLeftDown = null;
				obj.m_onLeftUp = null;
			}
			if (!((Object)(object)instance.m_menuList != (Object)null))
			{
				return;
			}
			try
			{
				AccessTools.Field(typeof(FejdStartup), "m_menuButtons")?.SetValue(instance, instance.m_menuList.GetComponentsInChildren<Button>());
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not update m_menuButtons via reflection: " + ex.Message));
			}
		}

		public static void BuildCustomPanel(FejdStartup instance)
		{
			//IL_0083: 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_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b3: Expected O, but got Unknown
			//IL_028f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Expected O, but got Unknown
			//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0311: Unknown result type (might be due to invalid IL or missing references)
			//IL_0336: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b3: Expected O, but got Unknown
			//IL_03db: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0407: Unknown result type (might be due to invalid IL or missing references)
			//IL_0413: Unknown result type (might be due to invalid IL or missing references)
			//IL_041f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0444: Unknown result type (might be due to invalid IL or missing references)
			//IL_044e: Expected O, but got Unknown
			//IL_04bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c6: Expected O, but got Unknown
			//IL_04ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0504: Unknown result type (might be due to invalid IL or missing references)
			//IL_0519: Unknown result type (might be due to invalid IL or missing references)
			//IL_052e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0542: Unknown result type (might be due to invalid IL or missing references)
			//IL_0575: Unknown result type (might be due to invalid IL or missing references)
			//IL_057c: Expected O, but got Unknown
			//IL_0598: Unknown result type (might be due to invalid IL or missing references)
			//IL_05a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_05ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_05dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_05f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_05fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_060a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0616: 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_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_069c: Unknown result type (might be due to invalid IL or missing references)
			//IL_06ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_06b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0726: Unknown result type (might be due to invalid IL or missing references)
			//IL_0730: Expected O, but got Unknown
			//IL_078b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0790: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_customMenuPanel != (Object)null)
			{
				Object.Destroy((Object)(object)_customMenuPanel);
			}
			object obj;
			if (!((Object)(object)GUIManager.CustomGUIFront != (Object)null))
			{
				GameObject mainMenu = instance.m_mainMenu;
				obj = ((mainMenu != null) ? mainMenu.transform.parent : null);
			}
			else
			{
				obj = GUIManager.CustomGUIFront.transform;
			}
			Transform val = (Transform)obj;
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"No suitable GUI root/parent found for BifrostConnect panel.");
				return;
			}
			_customMenuPanel = GUIManager.Instance.CreateWoodpanel(val, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 0f), 600f, 700f);
			_customMenuPanel.AddComponent<MenuEscapeHandler>().Instance = instance;
			GUIManager.Instance.CreateText("Server Directory", _customMenuPanel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -35f), GUIManager.Instance.AveriaSerifBold, 24, GUIManager.Instance.ValheimOrange, true, Color.black, 400f, 40f, false);
			_customMenuPanel.SetActive(false);
			((UnityEvent)GUIManager.Instance.CreateButton("Close", _customMenuPanel.transform, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(0f, 50f), 150f, 45f).GetComponent<Button>().onClick).AddListener((UnityAction)delegate
			{
				CloseMenu(instance);
			});
			Plugin.Log.LogInfo((object)$"BifrostConnect: Building directory UI for {Plugin.ServerList.Count} servers.");
			if (Plugin.ServerList.Count == 0)
			{
				GUIManager.Instance.CreateText("No servers configured.\nAdd servers to BepInEx/config/BifrostConnect_Servers.json", _customMenuPanel.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 0f), GUIManager.Instance.AveriaSerif, 18, Color.gray, false, Color.black, 500f, 100f, false);
			}
			else
			{
				GameObject val2 = new GameObject("Bifrost_ScrollView", new Type[4]
				{
					typeof(RectTransform),
					typeof(Image),
					typeof(RectMask2D),
					typeof(ScrollRect)
				});
				val2.transform.SetParent(_customMenuPanel.transform, false);
				RectTransform component = val2.GetComponent<RectTransform>();
				component.anchorMin = new Vector2(0.5f, 0.5f);
				component.anchorMax = new Vector2(0.5f, 0.5f);
				component.pivot = new Vector2(0.5f, 0.5f);
				component.anchoredPosition = new Vector2(0f, 15f);
				component.sizeDelta = new Vector2(500f, 500f);
				Image component2 = val2.GetComponent<Image>();
				((Graphic)component2).color = new Color(0f, 0f, 0f, 0.25f);
				((Graphic)component2).raycastTarget = true;
				ScrollRect component3 = val2.GetComponent<ScrollRect>();
				component3.horizontal = false;
				component3.vertical = true;
				component3.scrollSensitivity = 35f;
				component3.movementType = (MovementType)2;
				component3.viewport = component;
				GameObject val3 = new GameObject("Content", new Type[3]
				{
					typeof(RectTransform),
					typeof(VerticalLayoutGroup),
					typeof(ContentSizeFitter)
				});
				val3.transform.SetParent(val2.transform, false);
				RectTransform component4 = val3.GetComponent<RectTransform>();
				component4.anchorMin = new Vector2(0f, 1f);
				component4.anchorMax = new Vector2(1f, 1f);
				component4.pivot = new Vector2(0.5f, 1f);
				component4.anchoredPosition = Vector2.zero;
				component4.sizeDelta = Vector2.zero;
				VerticalLayoutGroup component5 = val3.GetComponent<VerticalLayoutGroup>();
				((HorizontalOrVerticalLayoutGroup)component5).spacing = 10f;
				((LayoutGroup)component5).padding = new RectOffset(10, 10, 10, 10);
				((LayoutGroup)component5).childAlignment = (TextAnchor)1;
				((HorizontalOrVerticalLayoutGroup)component5).childControlWidth = true;
				((HorizontalOrVerticalLayoutGroup)component5).childControlHeight = true;
				((HorizontalOrVerticalLayoutGroup)component5).childForceExpandWidth = false;
				((HorizontalOrVerticalLayoutGroup)component5).childForceExpandHeight = false;
				ContentSizeFitter component6 = val3.GetComponent<ContentSizeFitter>();
				component6.horizontalFit = (FitMode)0;
				component6.verticalFit = (FitMode)2;
				component3.content = component4;
				GameObject val4 = new GameObject("Bifrost_Scrollbar", new Type[3]
				{
					typeof(RectTransform),
					typeof(Image),
					typeof(Scrollbar)
				});
				val4.transform.SetParent(_customMenuPanel.transform, false);
				RectTransform component7 = val4.GetComponent<RectTransform>();
				component7.anchorMin = new Vector2(0.5f, 0.5f);
				component7.anchorMax = new Vector2(0.5f, 0.5f);
				component7.pivot = new Vector2(0.5f, 0.5f);
				component7.anchoredPosition = new Vector2(240f, 15f);
				component7.sizeDelta = new Vector2(12f, 490f);
				Scrollbar component8 = val4.GetComponent<Scrollbar>();
				component8.direction = (Direction)2;
				GameObject val5 = new GameObject("Sliding Area", new Type[1] { typeof(RectTransform) });
				val5.transform.SetParent(val4.transform, false);
				RectTransform component9 = val5.GetComponent<RectTransform>();
				component9.anchorMin = Vector2.zero;
				component9.anchorMax = Vector2.one;
				component9.sizeDelta = Vector2.zero;
				GameObject val6 = new GameObject("Handle", new Type[2]
				{
					typeof(RectTransform),
					typeof(Image)
				});
				val6.transform.SetParent(val5.transform, false);
				RectTransform component10 = val6.GetComponent<RectTransform>();
				component10.anchorMin = Vector2.zero;
				component10.anchorMax = Vector2.one;
				component10.sizeDelta = Vector2.zero;
				Image component11 = val6.GetComponent<Image>();
				component8.handleRect = component10;
				((Selectable)component8).targetGraphic = (Graphic)(object)component11;
				GUIManager.Instance.ApplyScrollbarStyle(component8);
				component3.verticalScrollbar = component8;
				component3.verticalScrollbarVisibility = (ScrollbarVisibility)1;
				foreach (ServerEntry server in Plugin.ServerList)
				{
					GameObject obj2 = GUIManager.Instance.CreateButton(server.Name, val3.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), Vector2.zero, 440f, 50f);
					LayoutElement obj3 = obj2.AddComponent<LayoutElement>();
					obj3.minWidth = 440f;
					obj3.preferredWidth = 440f;
					obj3.minHeight = 50f;
					obj3.preferredHeight = 50f;
					obj3.flexibleWidth = 0f;
					obj3.flexibleHeight = 0f;
					Button component12 = obj2.GetComponent<Button>();
					ServerEntry currentServer = server;
					((UnityEvent)component12.onClick).AddListener((UnityAction)delegate
					{
						OpenConfirmation(instance, currentServer);
					});
					Plugin.Log.LogInfo((object)("BifrostConnect: Added button for server '" + server.Name + "'"));
				}
				LayoutRebuilder.ForceRebuildLayoutImmediate(component4);
				component3.verticalNormalizedPosition = 1f;
				ManualLogSource log = Plugin.Log;
				Rect rect = component4.rect;
				log.LogInfo((object)$"BifrostConnect: Layout rebuilt. Total content height: {((Rect)(ref rect)).height}");
			}
			_customMenuPanel.SetActive(false);
		}

		public static void BuildConfirmationPanel(FejdStartup instance, ServerEntry server)
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: 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_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_028e: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0306: Unknown result type (might be due to invalid IL or missing references)
			//IL_0315: Unknown result type (might be due to invalid IL or missing references)
			//IL_0324: Unknown result type (might be due to invalid IL or missing references)
			//IL_0349: Unknown result type (might be due to invalid IL or missing references)
			//IL_0353: Expected O, but got Unknown
			//IL_0371: Unknown result type (might be due to invalid IL or missing references)
			//IL_0380: Unknown result type (might be due to invalid IL or missing references)
			//IL_038f: Unknown result type (might be due to invalid IL or missing references)
			//IL_03bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c8: Expected O, but got Unknown
			if ((Object)(object)_confirmPanel != (Object)null)
			{
				Object.Destroy((Object)(object)_confirmPanel);
			}
			object obj;
			if (!((Object)(object)GUIManager.CustomGUIFront != (Object)null))
			{
				GameObject mainMenu = instance.m_mainMenu;
				obj = ((mainMenu != null) ? mainMenu.transform.parent : null);
			}
			else
			{
				obj = GUIManager.CustomGUIFront.transform;
			}
			Transform val = (Transform)obj;
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log.LogWarning((object)"No suitable GUI root/parent found for confirmation panel.");
				return;
			}
			_confirmPanel = GUIManager.Instance.CreateWoodpanel(val, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0f, 0f), 500f, 340f);
			_confirmPanel.AddComponent<MenuEscapeHandler>().Instance = instance;
			GUIManager.Instance.CreateText("Join Server", _confirmPanel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -35f), GUIManager.Instance.AveriaSerifBold, 24, GUIManager.Instance.ValheimOrange, true, Color.black, 400f, 40f, false);
			GUIManager.Instance.CreateText(server.Name, _confirmPanel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -90f), GUIManager.Instance.AveriaSerifBold, 22, Color.white, true, Color.black, 460f, 35f, false);
			GUIManager.Instance.CreateText($"Address:  {server.IP}:{server.Port}", _confirmPanel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -135f), GUIManager.Instance.AveriaSerif, 18, new Color(0.9f, 0.9f, 0.9f), true, Color.black, 440f, 30f, false);
			string text = (string.IsNullOrEmpty(server.Password) ? "None" : "Saved (Auto-Fill)");
			GUIManager.Instance.CreateText("Password:  " + text, _confirmPanel.transform, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -175f), GUIManager.Instance.AveriaSerif, 18, new Color(0.9f, 0.9f, 0.9f), true, Color.black, 440f, 30f, false);
			((UnityEvent)GUIManager.Instance.CreateButton("Connect", _confirmPanel.transform, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(-100f, 45f), 160f, 45f).GetComponent<Button>().onClick).AddListener((UnityAction)delegate
			{
				ConnectToServer(instance, server);
			});
			ButtonClickedEvent onClick = GUIManager.Instance.CreateButton("Back", _confirmPanel.transform, new Vector2(0.5f, 0f), new Vector2(0.5f, 0f), new Vector2(100f, 45f), 160f, 45f).GetComponent<Button>().onClick;
			object obj2 = <>O.<0>__CloseConfirmation;
			if (obj2 == null)
			{
				UnityAction val2 = CloseConfirmation;
				<>O.<0>__CloseConfirmation = val2;
				obj2 = (object)val2;
			}
			((UnityEvent)onClick).AddListener((UnityAction)obj2);
			_confirmPanel.SetActive(false);
		}

		public static void OpenConfirmation(FejdStartup instance, ServerEntry server)
		{
			if ((Object)(object)_customMenuPanel != (Object)null)
			{
				_customMenuPanel.SetActive(false);
			}
			BuildConfirmationPanel(instance, server);
			if ((Object)(object)_confirmPanel != (Object)null)
			{
				_confirmPanel.SetActive(true);
			}
		}

		public static void CloseConfirmation()
		{
			if ((Object)(object)_confirmPanel != (Object)null)
			{
				_confirmPanel.SetActive(false);
			}
			if ((Object)(object)_customMenuPanel != (Object)null)
			{
				_customMenuPanel.SetActive(true);
				Canvas.ForceUpdateCanvases();
			}
		}

		private static void ConnectToServer(FejdStartup instance, ServerEntry server)
		{
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			Plugin.Log.LogInfo((object)$"Connecting to {server.Name} at {server.IP}:{server.Port}");
			if ((Object)(object)_confirmPanel != (Object)null)
			{
				_confirmPanel.SetActive(false);
			}
			if ((Object)(object)_customMenuPanel != (Object)null)
			{
				_customMenuPanel.SetActive(false);
			}
			ServerJoinDataDedicated val = default(ServerJoinDataDedicated);
			((ServerJoinDataDedicated)(ref val))..ctor(server.IP, (ushort)server.Port);
			ServerJoinData val2 = default(ServerJoinData);
			((ServerJoinData)(ref val2))..ctor(val);
			string text = ((!string.IsNullOrEmpty(server.Password)) ? server.Password : string.Empty);
			try
			{
				AccessTools.PropertySetter(typeof(FejdStartup), "ServerPassword")?.Invoke(null, new object[1] { text });
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not set FejdStartup.ServerPassword via reflection: " + ex.Message));
			}
			try
			{
				AccessTools.Field(typeof(ZNet), "m_serverPassword")?.SetValue(null, text);
			}
			catch
			{
			}
			try
			{
				AccessTools.Field(typeof(FejdStartup), "m_queuedJoinServer")?.SetValue(instance, val2);
			}
			catch (Exception ex2)
			{
				Plugin.Log.LogWarning((object)("Could not set FejdStartup.m_queuedJoinServer via reflection: " + ex2.Message));
			}
			instance.SetServerToJoin(val2);
			if ((Object)(object)instance.m_mainMenu != (Object)null)
			{
				instance.m_mainMenu.SetActive(false);
			}
			try
			{
				instance.OnStartGame();
			}
			catch (Exception ex3)
			{
				Plugin.Log.LogWarning((object)("OnStartGame failed: " + ex3.Message + ". Falling back to reflection."));
				try
				{
					AccessTools.Method(typeof(FejdStartup), "ShowCharacterSelection", (Type[])null, (Type[])null)?.Invoke(instance, null);
					if (SaveSystem.GetAllPlayerProfiles().Count == 0)
					{
						instance.OnCharacterNew();
					}
				}
				catch (Exception arg)
				{
					Plugin.Log.LogError((object)$"Failed to show character selection: {arg}");
				}
			}
		}

		public static void OpenMenu(FejdStartup instance)
		{
			Plugin.LoadServerConfig();
			BuildCustomPanel(instance);
			if ((Object)(object)instance.m_mainMenu != (Object)null)
			{
				instance.m_mainMenu.SetActive(false);
			}
			if ((Object)(object)_customMenuPanel != (Object)null)
			{
				_customMenuPanel.SetActive(true);
				Canvas.ForceUpdateCanvases();
			}
		}

		public static void CloseMenu(FejdStartup instance)
		{
			if ((Object)(object)_confirmPanel != (Object)null)
			{
				_confirmPanel.SetActive(false);
			}
			if ((Object)(object)_customMenuPanel != (Object)null)
			{
				_customMenuPanel.SetActive(false);
			}
			if ((Object)(object)instance.m_mainMenu != (Object)null)
			{
				instance.m_mainMenu.SetActive(true);
			}
		}

		public static void HandleEscape(FejdStartup instance)
		{
			if ((Object)(object)_confirmPanel != (Object)null && _confirmPanel.activeSelf)
			{
				CloseConfirmation();
			}
			else if ((Object)(object)_customMenuPanel != (Object)null && _customMenuPanel.activeSelf)
			{
				CloseMenu(instance);
			}
		}
	}
}
namespace BifrostConnect.Patches
{
	[HarmonyPatch(typeof(FejdStartup), "Start")]
	public static class MainMenuPatch
	{
		public static void Postfix(FejdStartup __instance)
		{
			try
			{
				Plugin.Log.LogInfo((object)"FejdStartup Start detected. Injecting Bifrost UI.");
				MenuBuilder.InjectMainMenuButton(__instance);
				MenuBuilder.BuildCustomPanel(__instance);
			}
			catch (Exception arg)
			{
				Plugin.Log.LogError((object)$"Exception during Bifrost UI injection: {arg}");
			}
		}
	}
}
namespace BifrostConnect.Models
{
	[Serializable]
	public class ServerEntry
	{
		public string Name = string.Empty;

		public string IP = string.Empty;

		public int Port = 2456;

		public string Password = string.Empty;
	}
	[Serializable]
	public class ServerListWrapper
	{
		public List<ServerEntry> Servers = new List<ServerEntry>();
	}
}