Decompiled source of ServerManager v1.0.9

ServerManager.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data;
using System.Data.SqlTypes;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Dynamic;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Sockets;
using System.Net.WebSockets;
using System.Numerics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Cronos;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mono.Cecil;
using Mono.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Bson;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Linq.JsonPath;
using Newtonsoft.Json.Schema;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Utilities;
using ServerManager.Commands;
using ServerManager.Configuration;
using ServerManager.Discord;
using ServerManager.Events;
using ServerManager.PlayerLogging;
using Steamworks;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Core.ObjectPool;
using YamlDotNet.Core.Tokens;
using YamlDotNet.Helpers;
using YamlDotNet.RepresentationModel;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.BufferedDeserialization;
using YamlDotNet.Serialization.BufferedDeserialization.TypeDiscriminators;
using YamlDotNet.Serialization.Callbacks;
using YamlDotNet.Serialization.Converters;
using YamlDotNet.Serialization.EventEmitters;
using YamlDotNet.Serialization.NamingConventions;
using YamlDotNet.Serialization.NodeDeserializers;
using YamlDotNet.Serialization.NodeTypeResolvers;
using YamlDotNet.Serialization.ObjectFactories;
using YamlDotNet.Serialization.ObjectGraphTraversalStrategies;
using YamlDotNet.Serialization.ObjectGraphVisitors;
using YamlDotNet.Serialization.Schemas;
using YamlDotNet.Serialization.TypeInspectors;
using YamlDotNet.Serialization.TypeResolvers;
using YamlDotNet.Serialization.Utilities;
using YamlDotNet.Serialization.ValueDeserializers;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("ServerManager")]
[assembly: AssemblyDescription("Steamworks-only integrity, authoritative characters, anti-cheat, events, and embedded Discord control")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("sighsorry")]
[assembly: AssemblyProduct("ServerManager")]
[assembly: AssemblyCopyright("Copyright © 2026 sighsorry")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")]
[assembly: AssemblyFileVersion("1.0.9")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.9.0")]
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;
		}
	}
}
namespace ServerManager
{
	internal static class ClientMenuBranding
	{
		private sealed class LabelOverride
		{
			internal TMP_Text Text { get; }

			internal string OriginalText { get; }

			internal bool OriginalEnableAutoSizing { get; }

			internal TextWrappingModes OriginalWrappingMode { get; }

			internal float OriginalFontSizeMin { get; }

			internal float OriginalFontSizeMax { get; }

			internal bool HadLocalizationSource { get; }

			internal string? LocalizationSource { get; }

			internal bool LocalizationDetached { get; set; }

			internal LabelOverride(TMP_Text text)
			{
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				//IL_002c: Unknown result type (might be due to invalid IL or missing references)
				Text = text;
				OriginalText = text.text;
				OriginalEnableAutoSizing = text.enableAutoSizing;
				OriginalWrappingMode = text.textWrappingMode;
				OriginalFontSizeMin = text.fontSizeMin;
				OriginalFontSizeMax = text.fontSizeMax;
				Localization instance = Localization.instance;
				if (instance != null && TryGetLocalizationTextMeshStrings(instance, out Dictionary<TMP_Text, string> textMeshStrings) && textMeshStrings.TryGetValue(text, out var value))
				{
					HadLocalizationSource = true;
					LocalizationSource = value;
				}
			}
		}

		private sealed class RemoteLogoLoad
		{
			internal readonly FejdStartup Startup;

			internal readonly Image Image;

			internal readonly string Source;

			internal readonly string? CachePath;

			internal readonly CancellationTokenSource Stop = new CancellationTokenSource();

			internal readonly Task<byte[]> Download;

			internal RemoteLogoLoad(FejdStartup startup, Image image, string source, Uri url, string? cachePath)
			{
				Startup = startup;
				Image = image;
				Source = source;
				CachePath = cachePath;
				CancellationToken token = Stop.Token;
				Download = Task.Run(() => DownloadLogoAsync(url, token));
			}
		}

		private sealed class MenuGuide
		{
			private readonly FejdStartup _startup;

			private readonly List<KeyValuePair<GameObject, bool>> _hidden = new List<KeyValuePair<GameObject, bool>>();

			private MenuTextPanel? _panel;

			private MenuTextPanel? _optionalPanel;

			private GameObject? _launcher;

			private GameObject? _dialog;

			private GameObject? _previousSelection;

			private bool _open;

			private bool _showMods;

			private Button? _modsButton;

			private Button? _guideButton;

			private Button? _closeButton;

			private OptionalModQuery? _optionalQuery;

			private OptionalModLobbyQuery? _optionalLobbyQuery;

			private bool _optionalLobbyMode;

			private string? _optionalEndpointInput;

			private bool _optionalFailed;

			private long _optionalRevision = -1L;

			private string? _optionalLanguage;

			private string? _language;

			private string? _hintEndpoint;

			private bool _visible;

			private void SetOpen(bool open)
			{
				_open = open;
				if (open)
				{
					EventSystem current = EventSystem.current;
					_previousSelection = ((current != null) ? current.currentSelectedGameObject : null);
					_dialog.SetActive(true);
					((Selectable)_dialog.GetComponentInChildren<Button>()).Select();
					return;
				}
				GameObject? dialog = _dialog;
				if (dialog != null)
				{
					dialog.SetActive(false);
				}
				if ((Object)(object)_previousSelection != (Object)null && _previousSelection.activeInHierarchy)
				{
					EventSystem current2 = EventSystem.current;
					if (current2 != null)
					{
						current2.SetSelectedGameObject(_previousSelection);
					}
				}
				_previousSelection = null;
			}

			internal bool HandleDialogInput()
			{
				if (!_open || !CanShow(_startup))
				{
					return false;
				}
				if (ZInput.GetKeyDown((KeyCode)27, true) || ZInput.GetButtonDown("JoyButtonB"))
				{
					SetOpen(open: false);
					return true;
				}
				return false;
			}

			private Button AddButton(Transform parent, string text, Vector2 position, UnityAction action)
			{
				//IL_0038: Unknown result type (might be due to invalid IL or missing references)
				//IL_003d: Unknown result type (might be due to invalid IL or missing references)
				//IL_004a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0050: Unknown result type (might be due to invalid IL or missing references)
				//IL_0055: Unknown result type (might be due to invalid IL or missing references)
				//IL_0056: Unknown result type (might be due to invalid IL or missing references)
				//IL_0057: Unknown result type (might be due to invalid IL or missing references)
				//IL_0069: Unknown result type (might be due to invalid IL or missing references)
				//IL_006f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0070: Unknown result type (might be due to invalid IL or missing references)
				//IL_0071: Unknown result type (might be due to invalid IL or missing references)
				//IL_0077: 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_007e: Unknown result type (might be due to invalid IL or missing references)
				//IL_008e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0098: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00be: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
				//IL_0110: Unknown result type (might be due to invalid IL or missing references)
				//IL_0115: Unknown result type (might be due to invalid IL or missing references)
				GameObject val = new GameObject("ServerManager " + text, new Type[3]
				{
					typeof(RectTransform),
					typeof(Image),
					typeof(Button)
				});
				val.transform.SetParent(parent, false);
				RectTransform val2 = (RectTransform)val.transform;
				Vector2 val3 = default(Vector2);
				((Vector2)(ref val3))..ctor(0.5f, 1f);
				val2.pivot = val3;
				Vector2 anchorMin = (val2.anchorMax = val3);
				val2.anchorMin = anchorMin;
				val2.anchoredPosition = position;
				val2.sizeDelta = new Vector2(150f, 36f);
				Image component = val.GetComponent<Image>();
				((Graphic)component).color = new Color(0.18f, 0.14f, 0.09f, 1f);
				TMP_Text obj = MenuTextPanel.CreateText(val.transform, _startup.m_connectionFailedError, "Label", 20f, new Color(1f, 0.8f, 0.4f));
				obj.text = text;
				obj.alignment = (TextAlignmentOptions)514;
				((Graphic)obj).raycastTarget = false;
				MenuTextPanel.Stretch(obj.rectTransform, Vector2.zero, Vector2.zero);
				Button component2 = val.GetComponent<Button>();
				((Selectable)component2).targetGraphic = (Graphic)(object)component;
				((UnityEvent)component2.onClick).AddListener(action);
				return component2;
			}

			private void EnsureDialog()
			{
				//IL_0030: 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_0046: Expected O, but got Unknown
				//IL_005b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0060: Unknown result type (might be due to invalid IL or missing references)
				//IL_0061: Unknown result type (might be due to invalid IL or missing references)
				//IL_0062: Unknown result type (might be due to invalid IL or missing references)
				//IL_0063: Unknown result type (might be due to invalid IL or missing references)
				//IL_0068: Unknown result type (might be due to invalid IL or missing references)
				//IL_0069: Unknown result type (might be due to invalid IL or missing references)
				//IL_0070: Unknown result type (might be due to invalid IL or missing references)
				//IL_0072: Unknown result type (might be due to invalid IL or missing references)
				//IL_0073: Unknown result type (might be due to invalid IL or missing references)
				//IL_0079: 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_00d3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00dd: Expected O, but got Unknown
				//IL_0115: Unknown result type (might be due to invalid IL or missing references)
				//IL_011a: 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)
				//IL_0129: Expected O, but got Unknown
				//IL_0148: 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_0192: Unknown result type (might be due to invalid IL or missing references)
				//IL_019c: Expected O, but got Unknown
				//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
				//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
				//IL_01cf: Expected O, but got Unknown
				//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
				//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
				//IL_0205: Expected O, but got Unknown
				//IL_0237: Unknown result type (might be due to invalid IL or missing references)
				//IL_0263: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)_launcher != (Object)null))
				{
					_launcher = ((Component)AddButton(_startup.m_mainMenu.transform, "Server Info", new Vector2(0f, -20f), (UnityAction)delegate
					{
						SetOpen(open: true);
					})).gameObject;
					RectTransform val = (RectTransform)_launcher.transform;
					Vector2 val2 = (val.pivot = Vector2.one);
					Vector2 anchorMin = (val.anchorMax = val2);
					val.anchorMin = anchorMin;
					val.anchoredPosition = new Vector2(-24f, -24f);
					_dialog = new GameObject("ServerManager Info", new Type[4]
					{
						typeof(RectTransform),
						typeof(Image),
						typeof(Canvas),
						typeof(GraphicRaycaster)
					});
					_dialog.SetActive(false);
					_dialog.transform.SetParent(_startup.m_mainMenu.transform, false);
					MenuTextPanel.Stretch((RectTransform)_dialog.transform, Vector2.zero, Vector2.zero);
					((Graphic)_dialog.GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0.94f);
					Canvas component = _dialog.GetComponent<Canvas>();
					component.overrideSorting = true;
					component.sortingOrder = 100;
					Button val4 = AddButton(_dialog.transform, "Guide", new Vector2(-160f, -20f), (UnityAction)delegate
					{
						_showMods = false;
					});
					_modsButton = AddButton(_dialog.transform, "Allowed Mods", new Vector2(0f, -20f), (UnityAction)delegate
					{
						_showMods = true;
					});
					Button val5 = AddButton(_dialog.transform, "Close", new Vector2(160f, -20f), (UnityAction)delegate
					{
						SetOpen(open: false);
					});
					_guideButton = val4;
					_closeButton = val5;
					Button[] array = (Button[])(object)new Button[3] { val4, _modsButton, val5 };
					for (int num = 0; num < array.Length; num++)
					{
						Button obj = array[num];
						Navigation navigation = default(Navigation);
						((Navigation)(ref navigation)).mode = (Mode)4;
						((Navigation)(ref navigation)).selectOnLeft = (Selectable)(object)array[(num + 2) % 3];
						((Navigation)(ref navigation)).selectOnRight = (Selectable)(object)array[(num + 1) % 3];
						((Selectable)obj).navigation = navigation;
					}
				}
			}

			internal MenuGuide(FejdStartup startup)
			{
				_startup = startup;
			}

			private static bool Active(GameObject? value)
			{
				if ((Object)(object)value != (Object)null)
				{
					return value.activeInHierarchy;
				}
				return false;
			}

			internal static bool CanShow(FejdStartup startup)
			{
				if (Active(startup.m_mainMenu) && Active(startup.m_menuList) && !Active(startup.m_connectionFailedPanel) && !Active(startup.m_worldVersionPanel) && !Active(startup.m_playerVersionPanel) && !Active(startup.m_newGameVersionPanel) && !Active(startup.m_ndaPanel) && !Active(startup.m_loading) && !Active(startup.m_pleaseWait) && !UnifiedPopup.IsVisible())
				{
					return !Feedback.IsVisible();
				}
				return false;
			}

			internal void Update(bool refreshText)
			{
				//IL_011a: 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)
				//IL_013e: Unknown result type (might be due to invalid IL or missing references)
				//IL_014a: Unknown result type (might be due to invalid IL or missing references)
				//IL_014f: Unknown result type (might be due to invalid IL or missing references)
				//IL_016f: Unknown result type (might be due to invalid IL or missing references)
				if (!CanShow(_startup))
				{
					if (_open)
					{
						SetOpen(open: false);
					}
					GameObject? launcher = _launcher;
					if (launcher != null)
					{
						launcher.SetActive(false);
					}
					SetVisible(visible: false);
					return;
				}
				if (_customMenuActive)
				{
					EnsureDialog();
					_launcher.SetActive(true);
					if (!_open)
					{
						SetVisible(visible: false);
						return;
					}
					_dialog.transform.SetAsLastSibling();
				}
				if (_panel == null)
				{
					_panel = new MenuTextPanel(_startup, left: false);
				}
				if (_customMenuActive)
				{
					_panel.UseDialog(_dialog.transform);
				}
				Localization instance = Localization.instance;
				string text = ((instance != null) ? instance.GetSelectedLanguage() : null) ?? "English";
				string text2 = ServerManagerPlugin.BrandingServerAddress?.Value ?? string.Empty;
				if ((Object)(object)_modsButton != (Object)null)
				{
					bool flag = !string.IsNullOrWhiteSpace(text2);
					if (((Selectable)_modsButton).interactable != flag)
					{
						((Selectable)_modsButton).interactable = flag;
						Navigation navigation = ((Selectable)_guideButton).navigation;
						((Navigation)(ref navigation)).selectOnRight = (Selectable)(object)(flag ? _modsButton : _closeButton);
						((Selectable)_guideButton).navigation = navigation;
						Navigation navigation2 = ((Selectable)_closeButton).navigation;
						((Navigation)(ref navigation2)).selectOnLeft = (Selectable)(object)(flag ? _modsButton : _guideButton);
						((Selectable)_closeButton).navigation = navigation2;
						if (!flag)
						{
							EventSystem current = EventSystem.current;
							if ((Object)(object)((current != null) ? current.currentSelectedGameObject : null) == (Object)(object)((Component)_modsButton).gameObject)
							{
								((Selectable)_guideButton).Select();
							}
						}
					}
					if (!((Selectable)_modsButton).interactable)
					{
						_showMods = false;
					}
				}
				if (refreshText || !string.Equals(_language, text, StringComparison.Ordinal) || !string.Equals(_hintEndpoint, text2, StringComparison.Ordinal))
				{
					_language = text;
					_hintEndpoint = text2;
					string text3 = string.Join("\n\n", PlayerLocalizer.Text("sm_menu_guide_character"), PlayerLocalizer.Text("sm_menu_guide_mods"), PlayerLocalizer.Text("sm_menu_guide_update"));
					if (ShouldShowWorldMenuHint(text2))
					{
						text3 = text3 + "\n\n" + PlayerLocalizer.Text("sm_menu_guide_worlds");
					}
					_panel.SetText(PlayerLocalizer.Text("sm_menu_guide_title"), text3);
				}
				SetVisible(visible: true);
				_panel.UpdateLayout();
				UpdateOptionalList(text2, text, refreshText);
				if (_customMenuActive)
				{
					_panel.SetVisible(!_showMods || string.IsNullOrWhiteSpace(text2));
					_optionalPanel?.SetVisible(_showMods && !string.IsNullOrWhiteSpace(text2));
				}
				if (_customMenuActive && _showMods)
				{
					_optionalPanel?.HandleGuideKeys();
				}
				else
				{
					_panel.HandleGuideKeys();
				}
			}

			private void UpdateOptionalList(string endpoint, string language, bool refreshText)
			{
				if (string.IsNullOrWhiteSpace(endpoint))
				{
					_optionalPanel?.SetVisible(visible: false);
					_optionalQuery?.Dispose();
					_optionalQuery = null;
					_optionalLobbyQuery?.Dispose();
					_optionalLobbyQuery = null;
					_optionalRevision = -1L;
				}
				else
				{
					if (_optionalFailed)
					{
						return;
					}
					try
					{
						if (!string.Equals(_optionalEndpointInput, endpoint, StringComparison.Ordinal))
						{
							_optionalEndpointInput = endpoint;
							bool flag = endpoint.Trim().StartsWith("steam:", StringComparison.OrdinalIgnoreCase);
							if (_optionalLobbyMode != flag)
							{
								_optionalQuery?.Pause();
								_optionalLobbyQuery?.Pause();
								_optionalLobbyMode = flag;
								_optionalRevision = -1L;
							}
						}
						bool optionalLobbyMode = _optionalLobbyMode;
						OptionalModQueryState state;
						bool isStale;
						long displayRevision;
						IReadOnlyList<OptionalModCatalogEntry> entries;
						if (optionalLobbyMode)
						{
							if (_optionalLobbyQuery == null)
							{
								_optionalLobbyQuery = new OptionalModLobbyQuery();
							}
							_optionalLobbyQuery.Tick(endpoint);
							state = _optionalLobbyQuery.State;
							isStale = _optionalLobbyQuery.IsStale;
							displayRevision = _optionalLobbyQuery.DisplayRevision;
							entries = _optionalLobbyQuery.Entries;
						}
						else
						{
							if (_optionalQuery == null)
							{
								_optionalQuery = new OptionalModQuery();
							}
							_optionalQuery.Tick(endpoint);
							state = _optionalQuery.State;
							isStale = _optionalQuery.IsStale;
							displayRevision = _optionalQuery.DisplayRevision;
							entries = _optionalQuery.Entries;
						}
						if (_optionalPanel == null)
						{
							_optionalPanel = new MenuTextPanel(_startup, left: true);
						}
						if (_customMenuActive)
						{
							_optionalPanel.UseDialog(_dialog.transform);
						}
						if (refreshText || _optionalRevision != displayRevision || !string.Equals(_optionalLanguage, language, StringComparison.Ordinal))
						{
							_optionalRevision = displayRevision;
							_optionalLanguage = language;
							string text = FormatOptionalList(state, isStale, entries, CaptureLoadedOptionalModVersions());
							if (optionalLobbyMode && (state == OptionalModQueryState.Unavailable || state == OptionalModQueryState.Unsupported))
							{
								text = text + "\n\n" + PlayerLocalizer.Text("sm_menu_optional_host_help");
							}
							_optionalPanel.SetText(PlayerLocalizer.Text("sm_menu_optional_title"), text);
						}
						_optionalPanel.SetVisible(!_customMenuActive || _showMods);
						_optionalPanel.UpdateLayout();
					}
					catch (Exception ex) when (!IntegrityCanonical.IsFatal(ex))
					{
						_optionalPanel?.Dispose();
						_optionalPanel = null;
						_optionalQuery?.Dispose();
						_optionalQuery = null;
						_optionalFailed = true;
						_optionalLobbyQuery?.Dispose();
						_optionalLobbyQuery = null;
						ServerManagerPlugin.Log.LogWarning((object)("Optional-mod menu preview unavailable: " + ex.Message));
					}
				}
			}

			internal void Reflow()
			{
				_panel?.Reflow();
			}

			internal void SetVisible(bool visible)
			{
				if (visible && !_visible)
				{
					CaptureTargets();
				}
				else if (!visible && _visible)
				{
					RestoreTargets();
					_optionalQuery?.Pause();
					_optionalLobbyQuery?.Pause();
				}
				_visible = visible;
				_panel?.SetVisible(visible && (!_customMenuActive || !_showMods));
				if (!visible)
				{
					_optionalPanel?.SetVisible(visible: false);
				}
				if (!visible)
				{
					return;
				}
				foreach (KeyValuePair<GameObject, bool> item in _hidden)
				{
					if ((Object)(object)item.Key != (Object)null)
					{
						item.Key.SetActive(false);
					}
				}
			}

			private bool IsSafeTarget(GameObject? target)
			{
				GameObject mainMenu = _startup.m_mainMenu;
				if ((Object)(object)mainMenu == (Object)null || (Object)(object)_startup.m_menuList == (Object)null)
				{
					return false;
				}
				Transform val = mainMenu.transform.Find("Logo/LOGO");
				if ((Object)(object)target != (Object)null && (Object)(object)target != (Object)(object)((Component)_startup).gameObject && (Object)(object)target != (Object)(object)mainMenu && (Object)(object)target != (Object)(object)_startup.m_menuList && !mainMenu.transform.IsChildOf(target.transform) && !_startup.m_menuList.transform.IsChildOf(target.transform))
				{
					if (!((Object)(object)val == (Object)null))
					{
						return !val.IsChildOf(target.transform);
					}
					return true;
				}
				return false;
			}

			private void Hide(GameObject? target)
			{
				if (!IsSafeTarget(target))
				{
					return;
				}
				foreach (KeyValuePair<GameObject, bool> item in _hidden)
				{
					if ((Object)(object)item.Key == (Object)(object)target)
					{
						return;
					}
				}
				_hidden.Add(new KeyValuePair<GameObject, bool>(target, target.activeSelf));
			}

			private void CaptureTargets()
			{
				if (_customMenuActive)
				{
					return;
				}
				ChangeLog[] componentsInChildren = ((Component)_startup).GetComponentsInChildren<ChangeLog>(true);
				foreach (ChangeLog val in componentsInChildren)
				{
					if (!((Object)(object)val.m_scrollbar != (Object)(object)_startup.m_patchLogScroll) && !((Object)(object)val.m_textField == (Object)null))
					{
						Scrollbar scrollbar = val.m_scrollbar;
						Transform val2 = ((scrollbar != null) ? ((Component)scrollbar).transform.parent : null);
						if ((Object)(object)val2 != (Object)null && val.m_textField.transform.IsChildOf(val2) && IsSafeTarget(((Component)val2).gameObject) && ((Object)(object)val.m_showPlayerLog == (Object)null || !val.m_showPlayerLog.transform.IsChildOf(val2)))
						{
							Hide(((Component)val2).gameObject);
							continue;
						}
						Hide(((Component)val.m_textField).gameObject);
						Scrollbar scrollbar2 = val.m_scrollbar;
						Hide((scrollbar2 != null) ? ((Component)scrollbar2).gameObject : null);
					}
				}
				Hide(_startup.m_moddedText);
				Button[] componentsInChildren2 = ((Component)_startup).GetComponentsInChildren<Button>(true);
				foreach (Button val3 in componentsInChildren2)
				{
					for (int j = 0; j < ((UnityEventBase)val3.onClick).GetPersistentEventCount(); j++)
					{
						if (((UnityEventBase)val3.onClick).GetPersistentTarget(j) == (Object)(object)_startup && ((UnityEventBase)val3.onClick).GetPersistentMethodName(j) == "OnMerchStoreButton")
						{
							Hide(((Component)val3).gameObject);
							break;
						}
					}
				}
			}

			private void RestoreTargets()
			{
				foreach (KeyValuePair<GameObject, bool> item in _hidden)
				{
					if ((Object)(object)item.Key != (Object)null)
					{
						item.Key.SetActive(item.Value);
					}
				}
				_hidden.Clear();
			}

			internal void Dispose()
			{
				if (_open)
				{
					SetOpen(open: false);
				}
				if ((Object)(object)_launcher != (Object)null)
				{
					Object.Destroy((Object)(object)_launcher);
				}
				if ((Object)(object)_dialog != (Object)null)
				{
					Object.Destroy((Object)(object)_dialog);
				}
				_launcher = (_dialog = null);
				_optionalQuery?.Dispose();
				_optionalQuery = null;
				_optionalLobbyQuery?.Dispose();
				_optionalLobbyQuery = null;
				_optionalPanel?.Dispose();
				_optionalPanel = null;
				_panel?.Dispose();
				_panel = null;
				RestoreTargets();
				_visible = false;
			}
		}

		private sealed class MenuTextPanel
		{
			private readonly FejdStartup _startup;

			private readonly bool _left;

			private RectTransform? _menu;

			private GameObject? _root;

			private ScrollRect? _scroll;

			private RectTransform? _content;

			private TMP_Text? _title;

			private TMP_Text? _body;

			private Scrollbar? _scrollbar;

			private Vector2 _lastSize;

			private bool _visible;

			private bool _needsLayout = true;

			private bool _inDialog;

			internal void UseDialog(Transform parent)
			{
				if (!_inDialog)
				{
					_inDialog = true;
					_root.transform.SetParent(parent, false);
					_needsLayout = true;
				}
			}

			internal MenuTextPanel(FejdStartup startup, bool left)
			{
				_startup = startup;
				_left = left;
				try
				{
					Create();
				}
				catch
				{
					Dispose();
					throw;
				}
			}

			internal void SetText(string title, string body)
			{
				_title.text = title;
				_body.text = body;
				_scroll.verticalNormalizedPosition = 1f;
				_needsLayout = true;
			}

			internal void UpdateLayout()
			{
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0021: 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)
				if (!_needsLayout)
				{
					Vector2 lastSize = _lastSize;
					Rect rect = _menu.rect;
					Vector2 val = lastSize - ((Rect)(ref rect)).size;
					if (!(((Vector2)(ref val)).sqrMagnitude > 0.25f))
					{
						return;
					}
				}
				Reflow();
				_needsLayout = false;
			}

			internal void HandleGuideKeys()
			{
				if (_scroll.vertical)
				{
					if (ZInput.GetKeyDown((KeyCode)281, true) || ZInput.GetButtonDown("JoyRBumper"))
					{
						_scroll.verticalNormalizedPosition = Mathf.Clamp01(_scroll.verticalNormalizedPosition - 0.25f);
					}
					else if (ZInput.GetKeyDown((KeyCode)280, true) || ZInput.GetButtonDown("JoyLBumper"))
					{
						_scroll.verticalNormalizedPosition = Mathf.Clamp01(_scroll.verticalNormalizedPosition + 0.25f);
					}
				}
			}

			private void Create()
			{
				//IL_0086: Unknown result type (might be due to invalid IL or missing references)
				//IL_0090: Expected O, but got Unknown
				//IL_00be: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c4: Expected O, but got Unknown
				//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e6: 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_00ef: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
				//IL_011d: Unknown result type (might be due to invalid IL or missing references)
				//IL_014c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0151: Unknown result type (might be due to invalid IL or missing references)
				//IL_0163: Unknown result type (might be due to invalid IL or missing references)
				//IL_0169: Expected O, but got Unknown
				//IL_016a: Unknown result type (might be due to invalid IL or missing references)
				//IL_016f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0191: Unknown result type (might be due to invalid IL or missing references)
				//IL_0197: Expected O, but got Unknown
				//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
				//IL_01b5: Expected O, but got Unknown
				//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
				//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
				//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
				//IL_021a: Unknown result type (might be due to invalid IL or missing references)
				//IL_024a: Unknown result type (might be due to invalid IL or missing references)
				_menu = _startup.m_mainMenu.GetComponent<RectTransform>();
				TMP_Text connectionFailedError = _startup.m_connectionFailedError;
				if ((Object)(object)_menu == (Object)null || (Object)(object)connectionFailedError == (Object)null)
				{
					throw new InvalidOperationException("The vanilla menu canvas/font is unavailable.");
				}
				_root = new GameObject(_left ? "ServerManagerOptionalMods" : "ServerManagerJoinGuide", new Type[3]
				{
					typeof(RectTransform),
					typeof(Image),
					typeof(ScrollRect)
				});
				_root.SetActive(false);
				_root.transform.SetParent((Transform)(object)_menu, false);
				RectTransform val = (RectTransform)_root.transform;
				Vector2 val2 = (val.pivot = (Vector2)(_left ? new Vector2(0f, 1f) : Vector2.one));
				Vector2 anchorMin = (val.anchorMax = val2);
				val.anchorMin = anchorMin;
				((Graphic)_root.GetComponent<Image>()).color = new Color(0.08f, 0.065f, 0.045f, 0.72f);
				GameObject val5 = new GameObject("Viewport", new Type[2]
				{
					typeof(RectTransform),
					typeof(RectMask2D)
				});
				val5.transform.SetParent((Transform)(object)val, false);
				RectTransform val6 = (RectTransform)val5.transform;
				Stretch(val6, Vector2.zero, Vector2.zero);
				GameObject val7 = new GameObject("Content", new Type[1] { typeof(RectTransform) });
				val7.transform.SetParent((Transform)(object)val6, false);
				_content = (RectTransform)val7.transform;
				_content.anchorMin = new Vector2(0f, 1f);
				_content.anchorMax = Vector2.one;
				_content.pivot = new Vector2(0.5f, 1f);
				_title = CreateText((Transform)(object)_content, connectionFailedError, "Heading", 26f, new Color(1f, 0.73f, 0.3f));
				_body = CreateText((Transform)(object)_content, connectionFailedError, "Tips", 20f, new Color(0.96f, 0.94f, 0.88f));
				_scroll = _root.GetComponent<ScrollRect>();
				_scroll.viewport = val6;
				_scroll.content = _content;
				_scroll.horizontal = false;
				_scroll.movementType = (MovementType)2;
				_scroll.inertia = false;
				_scroll.scrollSensitivity = 28f;
				_scrollbar = CreateScrollbar(val);
				_scroll.verticalScrollbar = _scrollbar;
				_scroll.verticalScrollbarVisibility = (ScrollbarVisibility)0;
			}

			internal static TMP_Text CreateText(Transform parent, TMP_Text fontSource, string name, float size, Color color)
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_001a: Expected O, but got Unknown
				//IL_0054: Unknown result type (might be due to invalid IL or missing references)
				//IL_0083: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
				GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
				val.SetActive(false);
				val.transform.SetParent(parent, false);
				TextMeshProUGUI obj = val.AddComponent<TextMeshProUGUI>();
				((TMP_Text)obj).font = fontSource.font;
				((TMP_Text)obj).fontSharedMaterial = fontSource.fontSharedMaterial;
				((TMP_Text)obj).fontSize = size;
				((Graphic)obj).color = color;
				((TMP_Text)obj).alignment = (TextAlignmentOptions)257;
				((TMP_Text)obj).enableAutoSizing = false;
				((TMP_Text)obj).textWrappingMode = (TextWrappingModes)1;
				((TMP_Text)obj).overflowMode = (TextOverflowModes)0;
				((TMP_Text)obj).richText = false;
				((TMP_Text)obj).margin = Vector4.zero;
				int num = (((TMP_Text)obj).maxVisibleLines = int.MaxValue);
				int maxVisibleCharacters = (((TMP_Text)obj).maxVisibleWords = num);
				((TMP_Text)obj).maxVisibleCharacters = maxVisibleCharacters;
				((TMP_Text)obj).rectTransform.anchorMin = new Vector2(0f, 1f);
				((TMP_Text)obj).rectTransform.anchorMax = Vector2.one;
				((TMP_Text)obj).rectTransform.pivot = new Vector2(0.5f, 1f);
				val.SetActive(true);
				return (TMP_Text)(object)obj;
			}

			internal static void Stretch(RectTransform rect, Vector2 minimum, Vector2 maximum)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				//IL_001e: Unknown result type (might be due to invalid IL or missing references)
				rect.anchorMin = Vector2.zero;
				rect.anchorMax = Vector2.one;
				rect.offsetMin = minimum;
				rect.offsetMax = maximum;
			}

			private static Scrollbar CreateScrollbar(RectTransform parent)
			{
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_0038: Expected O, but got Unknown
				//IL_004b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0050: Unknown result type (might be due to invalid IL or missing references)
				//IL_005b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0065: Unknown result type (might be due to invalid IL or missing references)
				//IL_0066: Unknown result type (might be due to invalid IL or missing references)
				//IL_0070: Unknown result type (might be due to invalid IL or missing references)
				//IL_007b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0085: Unknown result type (might be due to invalid IL or missing references)
				//IL_0090: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fd: Expected O, but got Unknown
				//IL_012b: Unknown result type (might be due to invalid IL or missing references)
				//IL_013b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0140: Unknown result type (might be due to invalid IL or missing references)
				//IL_0145: Unknown result type (might be due to invalid IL or missing references)
				//IL_014f: Expected O, but got Unknown
				//IL_0163: Unknown result type (might be due to invalid IL or missing references)
				//IL_016d: Expected O, but got Unknown
				//IL_0177: Unknown result type (might be due to invalid IL or missing references)
				//IL_0185: Unknown result type (might be due to invalid IL or missing references)
				GameObject val = new GameObject("ScrollTrack", new Type[3]
				{
					typeof(RectTransform),
					typeof(Image),
					typeof(Scrollbar)
				});
				val.transform.SetParent((Transform)(object)parent, false);
				RectTransform val2 = (RectTransform)val.transform;
				val2.anchorMin = new Vector2(1f, 0f);
				val2.anchorMax = Vector2.one;
				val2.pivot = new Vector2(1f, 0.5f);
				val2.sizeDelta = new Vector2(6f, -40f);
				val2.anchoredPosition = new Vector2(-9f, 0f);
				((Graphic)val.GetComponent<Image>()).color = new Color(1f, 1f, 1f, 0.09f);
				GameObject val3 = new GameObject("Handle", new Type[2]
				{
					typeof(RectTransform),
					typeof(Image)
				});
				val3.transform.SetParent(val.transform, false);
				Image component = val3.GetComponent<Image>();
				((Graphic)component).color = new Color(0.85f, 0.72f, 0.48f, 0.8f);
				Stretch((RectTransform)val3.transform, Vector2.zero, Vector2.zero);
				Scrollbar component2 = val.GetComponent<Scrollbar>();
				component2.direction = (Direction)2;
				component2.handleRect = (RectTransform)val3.transform;
				((Selectable)component2).targetGraphic = (Graphic)(object)component;
				Navigation navigation = default(Navigation);
				((Navigation)(ref navigation)).mode = (Mode)0;
				((Selectable)component2).navigation = navigation;
				return component2;
			}

			internal void Reflow()
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				//IL_0043: Unknown result type (might be due to invalid IL or missing references)
				//IL_0048: Unknown result type (might be due to invalid IL or missing references)
				//IL_0078: Unknown result type (might be due to invalid IL or missing references)
				//IL_008f: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fb: 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_012d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0139: Unknown result type (might be due to invalid IL or missing references)
				//IL_0140: Expected O, but got Unknown
				//IL_018e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0227: Unknown result type (might be due to invalid IL or missing references)
				//IL_0232: Unknown result type (might be due to invalid IL or missing references)
				//IL_0253: Unknown result type (might be due to invalid IL or missing references)
				//IL_025e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0273: Unknown result type (might be due to invalid IL or missing references)
				//IL_0278: Unknown result type (might be due to invalid IL or missing references)
				//IL_027e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0297: Unknown result type (might be due to invalid IL or missing references)
				//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
				//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
				//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
				//IL_02f0: Unknown result type (might be due to invalid IL or missing references)
				//IL_0305: Unknown result type (might be due to invalid IL or missing references)
				//IL_0321: Unknown result type (might be due to invalid IL or missing references)
				//IL_0344: Unknown result type (might be due to invalid IL or missing references)
				//IL_037c: Unknown result type (might be due to invalid IL or missing references)
				//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
				//IL_01fe: 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_0201: Unknown result type (might be due to invalid IL or missing references)
				//IL_0208: Unknown result type (might be due to invalid IL or missing references)
				//IL_021b: Unknown result type (might be due to invalid IL or missing references)
				Rect rect = _menu.rect;
				_lastSize = ((Rect)(ref rect)).size;
				float verticalNormalizedPosition = _scroll.verticalNormalizedPosition;
				float y = _lastSize.y;
				Vector2 val = CalculateGuideSize(_lastSize.x, y, 0f);
				if (_inDialog)
				{
					val.x = Mathf.Min(800f, _lastSize.x * 0.9f);
				}
				float num = Mathf.Min(20f, val.x * 0.1f);
				float num2 = Mathf.Min(28f, val.x * 0.14f);
				float num3 = Mathf.Max(1f, val.x - num - num2);
				float num4 = _title.GetPreferredValues(_title.text, num3, float.PositiveInfinity).y + 4f;
				float num5 = _body.GetPreferredValues(_body.text, num3, float.PositiveInfinity).y + 4f;
				float num6 = num4 + 16f + num5;
				val = CalculateGuideSize(_lastSize.x, y, num6);
				RectTransform val2 = (RectTransform)_root.transform;
				val2.anchoredPosition = new Vector2((_left ? 1f : (-1f)) * Mathf.Min(24f, _lastSize.x * 0.05f), 0f - Mathf.Min(24f, _lastSize.y * 0.05f));
				if (_inDialog)
				{
					((Vector2)(ref val))..ctor(Mathf.Min(800f, _lastSize.x * 0.9f), Mathf.Max(1f, _lastSize.y - 100f));
					Vector2 val3 = default(Vector2);
					((Vector2)(ref val3))..ctor(0.5f, 1f);
					val2.pivot = val3;
					Vector2 anchorMin = (val2.anchorMax = val3);
					val2.anchorMin = anchorMin;
					val2.anchoredPosition = new Vector2(0f, -76f);
				}
				val2.sizeDelta = val;
				float num7 = Mathf.Min(20f, val.y * 0.1f);
				Stretch(_scroll.viewport, new Vector2(num, num7), new Vector2(0f - num2, 0f - num7));
				RectTransform val5 = (RectTransform)((Component)_scrollbar).transform;
				val5.sizeDelta = new Vector2(Mathf.Min(6f, val.x * 0.04f), -2f * num7);
				val5.anchoredPosition = new Vector2(0f - Mathf.Min(9f, val.x * 0.05f), 0f);
				_content.sizeDelta = new Vector2(0f, num6);
				_title.rectTransform.sizeDelta = new Vector2(0f, num4);
				_title.rectTransform.anchoredPosition = Vector2.zero;
				_body.rectTransform.sizeDelta = new Vector2(0f, num5);
				_body.rectTransform.anchoredPosition = new Vector2(0f, 0f - num4 - 16f);
				val2.ForceUpdateRectTransforms();
				_title.ForceMeshUpdate(false, false);
				_body.ForceMeshUpdate(false, false);
				_scroll.vertical = num6 > Mathf.Max(1f, val.y - 2f * num7) + 0.5f;
				((Component)_scrollbar).gameObject.SetActive(_scroll.vertical);
				_scroll.verticalNormalizedPosition = (_scroll.vertical ? Mathf.Clamp01(verticalNormalizedPosition) : 1f);
			}

			internal void SetVisible(bool visible)
			{
				if (!((Object)(object)_root == (Object)null))
				{
					if (visible && !_visible)
					{
						_scroll.verticalNormalizedPosition = 1f;
						_needsLayout = true;
					}
					_visible = visible;
					_root.SetActive(visible);
				}
			}

			internal void Dispose()
			{
				_visible = false;
				if ((Object)(object)_root != (Object)null)
				{
					_root.SetActive(false);
					Object.Destroy((Object)(object)_root);
				}
				_root = null;
			}
		}

		private enum LogoDownloadFailure
		{
			HttpStatus,
			Network,
			Redirect,
			TooLarge,
			InvalidPng
		}

		private sealed class LogoDownloadException : Exception
		{
			internal readonly LogoDownloadFailure Failure;

			internal readonly int Status;

			internal LogoDownloadException(LogoDownloadFailure failure, int status = 0)
				: base("HTTPS logo download failed.")
			{
				Failure = failure;
				Status = status;
			}
		}

		internal const ushort DefaultServerPort = 2456;

		internal const int MaximumEndpointCharacters = 512;

		internal const int MaximumLogoBytes = 8388608;

		internal const int MaximumLogoDimension = 4096;

		internal const long MaximumLogoPixels = 16777216L;

		internal const int MaximumLogoUrlCharacters = 2048;

		internal const int LogoDownloadTimeoutSeconds = 30;

		internal const int MaximumLogoRedirects = 3;

		private static readonly FieldInfo? QueuedJoinServerField = AccessTools.Field(typeof(FejdStartup), "m_queuedJoinServer");

		private static readonly PropertyInfo? ServerPasswordProperty = AccessTools.Property(typeof(FejdStartup), "ServerPassword");

		private static readonly FieldInfo? LocalizationTextMeshStringsField = AccessTools.Field(typeof(Localization), "textMeshStrings");

		private static FejdStartup? _startup;

		private static LabelOverride? _mainButtonLabel;

		private static LabelOverride? _characterButtonLabel;

		private static bool _armed;

		private static bool _passwordAwaitingHandshake;

		private static bool _brandedJoinDispatched;

		private static string _pendingPassword = string.Empty;

		private static string? _ownedPassword;

		private static string? _previousPassword;

		private static bool _passwordWasOverridden;

		private static Image? _logoImage;

		private static Sprite? _vanillaLogo;

		private static bool _vanillaLogoPreserveAspect;

		private static Sprite? _customLogo;

		private static Texture2D? _customLogoTexture;

		private static string? _logoSource;

		private static RemoteLogoLoad? _remoteLogoLoad;

		private static string? _remoteLogoAttemptedSource;

		private static string _lastEndpointWarning = string.Empty;

		private static string _lastLogoWarning = string.Empty;

		private static string _lastQueuedJoinAccessWarning = string.Empty;

		private static string _lastServerPasswordAccessWarning = string.Empty;

		private static string _lastLocalizationCacheAccessWarning = string.Empty;

		private static MenuGuide? _menuGuide;

		private static bool _menuGuideFailed;

		private static bool _customMenuActive;

		private static bool IsCustomMenuActive()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Expected O, but got Unknown
			if (!Chainloader.PluginInfos.TryGetValue("rdmods.custommainmenu", out var value) || (Object)(object)value.Instance == (Object)null)
			{
				return false;
			}
			ConfigEntry<bool> val = default(ConfigEntry<bool>);
			if (value.Instance.Config.TryGetEntry<bool>(new ConfigDefinition("General", "Enabled"), ref val))
			{
				return val.Value;
			}
			return true;
		}

		private static void RefreshMenuCompatibility(FejdStartup startup)
		{
			bool flag = IsCustomMenuActive();
			if (flag != _customMenuActive)
			{
				_customMenuActive = flag;
				ResetMenuGuide();
				ApplyLogo(startup);
			}
		}

		internal static bool BeforeUiUpdate()
		{
			MenuGuide? menuGuide = _menuGuide;
			if (menuGuide == null)
			{
				return true;
			}
			return !menuGuide.HandleDialogInput();
		}

		private static void ResetMenuGuide()
		{
			_menuGuide?.Dispose();
			_menuGuide = null;
			_menuGuideFailed = false;
		}

		private static void UpdateMenuGuide(FejdStartup startup, bool refreshText = false)
		{
			if (!CanUseClientUi(startup))
			{
				ResetMenuGuide();
				return;
			}
			ObserveStartup(startup);
			if (_menuGuideFailed)
			{
				return;
			}
			try
			{
				if (_menuGuide == null)
				{
					_menuGuide = new MenuGuide(startup);
				}
				_menuGuide.Update(refreshText);
			}
			catch (Exception ex) when (!IntegrityCanonical.IsFatal(ex))
			{
				ResetMenuGuide();
				_menuGuideFailed = true;
				ServerManagerPlugin.Log.LogWarning((object)("Client menu guidance was unavailable; vanilla UI restored: " + ex.Message));
			}
		}

		internal static bool ShouldShowWorldMenuHint(string? endpoint)
		{
			string host;
			ushort port;
			string rejection;
			if (endpoint == null || !endpoint.Trim().StartsWith("steam:", StringComparison.OrdinalIgnoreCase))
			{
				return TryParseDedicatedEndpoint(endpoint, out host, out port, out rejection);
			}
			ulong host2;
			return OptionalModLobbyQuery.TryParseHostEndpoint(endpoint, out host2);
		}

		internal static Vector2 CalculateGuideSize(float menuWidth, float menuHeight, float preferredHeight)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			if (float.IsNaN(menuWidth) || float.IsInfinity(menuWidth) || menuWidth <= 0f || float.IsNaN(menuHeight) || float.IsInfinity(menuHeight) || menuHeight <= 0f)
			{
				return Vector2.zero;
			}
			float num = Mathf.Min(440f, menuWidth * 0.27f);
			float num2 = menuHeight - Mathf.Min(48f, menuHeight * 0.1f);
			float num3 = ((float.IsNaN(preferredHeight) || float.IsInfinity(preferredHeight)) ? num2 : (Mathf.Max(0f, preferredHeight) + 40f));
			return new Vector2(num, Mathf.Min(num2, num3));
		}

		private static IReadOnlyDictionary<string, System.Version> CaptureLoadedOptionalModVersions()
		{
			Dictionary<string, System.Version> dictionary = new Dictionary<string, System.Version>(StringComparer.Ordinal);
			try
			{
				foreach (PluginInfo value in Chainloader.PluginInfos.Values)
				{
					object obj;
					if (value == null)
					{
						obj = null;
					}
					else
					{
						BepInPlugin metadata = value.Metadata;
						obj = ((metadata != null) ? metadata.Version : null);
					}
					if (!((System.Version?)obj == null) && !((Object)(object)value.Instance == (Object)null) && IntegrityCanonical.TryNormalizeGuid(value.Metadata.GUID, IntegrityLimits.Default, "manifest.invalid_guid", out string canonical, out IntegrityDiagnostic _))
					{
						if (dictionary.ContainsKey(canonical))
						{
							dictionary.Clear();
							return dictionary;
						}
						dictionary.Add(canonical, value.Metadata.Version);
					}
				}
			}
			catch (Exception exception) when (!IntegrityCanonical.IsFatal(exception))
			{
				dictionary.Clear();
			}
			return dictionary;
		}

		internal static bool IsOptionalModLoaded(OptionalModCatalogEntry entry, IReadOnlyDictionary<string, System.Version>? loaded)
		{
			if (loaded == null || !loaded.TryGetValue(entry.PluginGuid, out System.Version value))
			{
				return false;
			}
			foreach (string version in entry.Versions)
			{
				if (System.Version.TryParse(version, out System.Version result) && result.Equals(value))
				{
					return true;
				}
			}
			return false;
		}

		internal static string FormatOptionalList(OptionalModQueryState state, bool stale, IReadOnlyList<OptionalModCatalogEntry> entries, IReadOnlyDictionary<string, System.Version>? loaded)
		{
			StringBuilder stringBuilder = new StringBuilder(PlayerLocalizer.Text(state switch
			{
				OptionalModQueryState.Loading => "sm_menu_optional_loading", 
				OptionalModQueryState.Unsupported => "sm_menu_optional_unsupported", 
				OptionalModQueryState.TooLarge => "sm_menu_optional_too_large", 
				OptionalModQueryState.Unavailable => "sm_menu_optional_unavailable", 
				_ => "sm_menu_optional_note", 
			}));
			if (stale)
			{
				stringBuilder.Append("\n\n").Append(PlayerLocalizer.Text("sm_menu_optional_stale"));
			}
			if (state != OptionalModQueryState.Available && !stale)
			{
				return stringBuilder.ToString();
			}
			if (entries.Count == 0)
			{
				return stringBuilder.Append("\n\n").Append(PlayerLocalizer.Text("sm_menu_optional_empty")).ToString();
			}
			int num = 0;
			foreach (OptionalModCatalogEntry entry in entries)
			{
				if (!IsOptionalModLoaded(entry, loaded))
				{
					num++;
					stringBuilder.Append("\n\n").Append(entry.Name).Append("\n");
					stringBuilder.Append((entry.Versions.Count == 0) ? PlayerLocalizer.Text("sm_menu_optional_version_unknown") : string.Join(", ", entry.Versions));
				}
			}
			if (num == 0)
			{
				stringBuilder.Append("\n\n").Append(PlayerLocalizer.Text("sm_menu_optional_installed"));
			}
			return stringBuilder.ToString();
		}

		internal static bool TryParseDedicatedEndpoint(string? value, out string host, out ushort port, out string rejection)
		{
			host = string.Empty;
			port = 0;
			rejection = string.Empty;
			string text = value?.Trim() ?? string.Empty;
			if (text.Length == 0)
			{
				rejection = "Server Address is empty.";
				return false;
			}
			if (text.Length > 512)
			{
				rejection = "Server Address is too long.";
				return false;
			}
			string text2 = text;
			foreach (char c in text2)
			{
				if (char.IsControl(c) || char.IsWhiteSpace(c))
				{
					rejection = "Server Address may not contain whitespace or control characters.";
					return false;
				}
			}
			if (text.IndexOf("://", StringComparison.Ordinal) >= 0 || text.IndexOf('/') >= 0 || text.IndexOf('\\') >= 0 || text.IndexOf('@') >= 0 || text.IndexOf('?') >= 0 || text.IndexOf('#') >= 0)
			{
				rejection = "Server Address must be a host or IP with an optional port, not a URL.";
				return false;
			}
			ushort port2 = 2456;
			string ipString;
			if (text[0] == '[')
			{
				int num = text.IndexOf(']');
				if (num <= 1)
				{
					rejection = "The bracketed IPv6 host is invalid.";
					return false;
				}
				ipString = text.Substring(1, num - 1);
				string text3 = text.Substring(num + 1);
				if (text3.Length > 0 && (text3[0] != ':' || !TryParsePort(text3.Substring(1), out port2)))
				{
					rejection = "The server port is invalid.";
					return false;
				}
				if (!IPAddress.TryParse(ipString, out IPAddress address) || address.AddressFamily != AddressFamily.InterNetworkV6)
				{
					rejection = "The bracketed host is not a valid IPv6 address.";
					return false;
				}
				ipString = address.ToString();
			}
			else
			{
				int num2 = 0;
				text2 = text;
				for (int i = 0; i < text2.Length; i++)
				{
					if (text2[i] == ':')
					{
						num2++;
					}
				}
				switch (num2)
				{
				case 0:
					ipString = text;
					break;
				case 1:
				{
					int num3 = text.LastIndexOf(':');
					ipString = text.Substring(0, num3);
					if (!TryParsePort(text.Substring(num3 + 1), out port2))
					{
						rejection = "The server port is invalid.";
						return false;
					}
					break;
				}
				default:
				{
					if (!IPAddress.TryParse(text, out IPAddress address2) || address2.AddressFamily != AddressFamily.InterNetworkV6)
					{
						rejection = "IPv6 addresses with an explicit port must use [address]:port.";
						return false;
					}
					ipString = address2.ToString();
					break;
				}
				}
			}
			if (ipString.Length == 0 || ipString.Length > 253)
			{
				rejection = "The server host is empty or too long.";
				return false;
			}
			if (IPAddress.TryParse(ipString, out IPAddress address3))
			{
				ipString = address3.ToString();
			}
			else if (Uri.CheckHostName(ipString) != UriHostNameType.Dns)
			{
				rejection = "The server host is not a valid DNS name or IP address.";
				return false;
			}
			host = ipString;
			port = port2;
			return true;
		}

		internal static bool TryParseLogoUrl(string? value, out Uri url, out string rejection)
		{
			url = null;
			rejection = "Logo URL must be an HTTPS address without credentials, fragments or whitespace.";
			string text = value ?? string.Empty;
			if (text.Length == 0 || text.Length > 2048)
			{
				return false;
			}
			string text2 = text;
			foreach (char c in text2)
			{
				if (char.IsControl(c) || char.IsWhiteSpace(c))
				{
					return false;
				}
			}
			if (text.IndexOf('\\') >= 0 || !Uri.TryCreate(text, UriKind.Absolute, out Uri result) || result.Scheme != Uri.UriSchemeHttps || string.IsNullOrEmpty(result.Host) || result.UserInfo.Length != 0 || result.Fragment.Length != 0 || result.HostNameType == UriHostNameType.Unknown)
			{
				return false;
			}
			url = result;
			rejection = string.Empty;
			return true;
		}

		private static string LogoDownloadFailureMessage(Exception exception)
		{
			if (exception is TimeoutException)
			{
				return "The HTTPS menu logo download timed out after " + 30.ToString(CultureInfo.InvariantCulture) + " seconds; keeping the cached or vanilla logo.";
			}
			if (exception is OperationCanceledException)
			{
				return "The HTTPS menu logo download was cancelled; keeping the cached or vanilla logo.";
			}
			if (exception is LogoDownloadException ex)
			{
				switch (ex.Failure)
				{
				case LogoDownloadFailure.HttpStatus:
				{
					string text;
					if (ex.Status < 100 || ex.Status > 599)
					{
						text = string.Empty;
					}
					else
					{
						int status = ex.Status;
						text = " (HTTP " + status.ToString(CultureInfo.InvariantCulture) + ")";
					}
					return "The HTTPS menu logo server returned an HTTP error" + text + "; keeping the cached or vanilla logo.";
				}
				case LogoDownloadFailure.Network:
					return "The HTTPS menu logo download failed (network/TLS transport error); keeping the cached or vanilla logo.";
				case LogoDownloadFailure.Redirect:
					return "The HTTPS menu logo redirect was invalid or exceeded " + 3.ToString(CultureInfo.InvariantCulture) + " redirects; keeping the cached or vanilla logo.";
				case LogoDownloadFailure.TooLarge:
					return "The HTTPS menu logo response exceeds the 8 MiB size limit; keeping the cached or vanilla logo.";
				case LogoDownloadFailure.InvalidPng:
					return "The HTTPS menu logo response failed PNG validation; keeping the cached or vanilla logo.";
				}
			}
			return "The HTTPS menu logo download failed; keeping the cached or vanilla logo.";
		}

		internal static async Task<byte[]> DownloadLogoAsync(Uri url, CancellationToken cancellation, HttpMessageHandler? handler = null)
		{
			if (url == null || !url.IsAbsoluteUri || !TryParseLogoUrl(url.AbsoluteUri, out Uri destination, out string rejection))
			{
				throw new InvalidDataException("Invalid HTTPS logo address.");
			}
			using CancellationTokenSource deadline = CancellationTokenSource.CreateLinkedTokenSource(new CancellationToken[1] { cancellation });
			deadline.CancelAfter(TimeSpan.FromSeconds(30.0));
			CancellationToken token = deadline.Token;
			try
			{
				if (handler == null)
				{
					handler = (HttpMessageHandler?)new HttpClientHandler
					{
						AllowAutoRedirect = false,
						UseCookies = false,
						UseDefaultCredentials = false,
						Credentials = null,
						AutomaticDecompression = DecompressionMethods.None,
						MaxResponseHeadersLength = 16
					};
				}
				HttpClient client = new HttpClient(handler, true)
				{
					Timeout = Timeout.InfiniteTimeSpan
				};
				try
				{
					int redirects = 0;
					while (true)
					{
						token.ThrowIfCancellationRequested();
						HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, destination);
						int height;
						try
						{
							request.Headers.Accept.ParseAdd("image/png");
							HttpResponseMessage response = await AwaitLogoTask(client.SendAsync(request, (HttpCompletionOption)1, token), token, delegate(HttpResponseMessage late)
							{
								late.Dispose();
							}).ConfigureAwait(continueOnCapturedContext: false);
							try
							{
								int statusCode = (int)response.StatusCode;
								switch (statusCode)
								{
								case 301:
								case 302:
								case 303:
								case 307:
								case 308:
								{
									Uri location = response.Headers.Location;
									if (redirects >= 3 || location == null || !Uri.TryCreate(destination, location, out Uri result) || !TryParseLogoUrl(result.AbsoluteUri, out destination, out rejection))
									{
										throw new LogoDownloadException(LogoDownloadFailure.Redirect);
									}
									break;
								}
								default:
									throw new LogoDownloadException(LogoDownloadFailure.HttpStatus, statusCode);
								case 200:
								{
									if (response.Content == null)
									{
										throw new LogoDownloadException(LogoDownloadFailure.InvalidPng);
									}
									if (response.Content.Headers.ContentLength > 8388608)
									{
										throw new LogoDownloadException(LogoDownloadFailure.TooLarge);
									}
									using Stream stream = await AwaitLogoTask(response.Content.ReadAsStreamAsync(), token, delegate(Stream late)
									{
										late.Dispose();
									}).ConfigureAwait(continueOnCapturedContext: false);
									using MemoryStream output = new MemoryStream();
									byte[] buffer = new byte[16384];
									while (true)
									{
										int num = await AwaitLogoTask(stream.ReadAsync(buffer, 0, buffer.Length, token), token).ConfigureAwait(continueOnCapturedContext: false);
										token.ThrowIfCancellationRequested();
										if (num == 0)
										{
											break;
										}
										if (output.Length + num > 8388608)
										{
											throw new LogoDownloadException(LogoDownloadFailure.TooLarge);
										}
										output.Write(buffer, 0, num);
									}
									byte[] array = output.ToArray();
									if (!TryValidatePng(array, out int _, out height, out rejection))
									{
										throw new LogoDownloadException(LogoDownloadFailure.InvalidPng);
									}
									return array;
								}
								}
							}
							finally
							{
								((IDisposable)response)?.Dispose();
							}
						}
						finally
						{
							((IDisposable)request)?.Dispose();
						}
						height = redirects + 1;
						redirects = height;
					}
				}
				finally
				{
					((IDisposable)client)?.Dispose();
				}
			}
			catch (OperationCanceledException) when (!cancellation.IsCancellationRequested && deadline.IsCancellationRequested)
			{
				throw new TimeoutException("HTTPS logo download deadline exceeded.");
			}
			catch (OperationCanceledException)
			{
				throw;
			}
			catch (LogoDownloadException)
			{
				throw;
			}
			catch (Exception exception) when (!IntegrityCanonical.IsFatal(exception))
			{
				throw new LogoDownloadException(LogoDownloadFailure.Network);
			}
		}

		private static async Task<T> AwaitLogoTask<T>(Task<T> task, CancellationToken token, Action<T>? abandoned = null)
		{
			if (task.IsCompleted)
			{
				return await task.ConfigureAwait(continueOnCapturedContext: false);
			}
			TaskCompletionSource<bool> cancelled = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
			using (token.Register(delegate
			{
				cancelled.TrySetResult(result: true);
			}))
			{
				if (await Task.WhenAny(new Task[2] { task, cancelled.Task }).ConfigureAwait(continueOnCapturedContext: false) != task)
				{
					task.ContinueWith(delegate(Task<T> completed)
					{
						if (completed.IsFaulted)
						{
							_ = completed.Exception;
						}
						else if (completed.Status == TaskStatus.RanToCompletion && abandoned != null)
						{
							try
							{
								abandoned(completed.Result);
							}
							catch (Exception)
							{
							}
						}
					}, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
					throw new OperationCanceledException(token);
				}
				return await task.ConfigureAwait(continueOnCapturedContext: false);
			}
		}

		internal static string GetLogoCachePath(string cacheRoot, Uri url)
		{
			if (string.IsNullOrWhiteSpace(cacheRoot) || url == null || !url.IsAbsoluteUri || !TryParseLogoUrl(url.AbsoluteUri, out Uri url2, out string _))
			{
				throw new InvalidDataException("The logo cache location is unavailable.");
			}
			using SHA256 sHA = SHA256.Create();
			string text = BitConverter.ToString(sHA.ComputeHash(Encoding.UTF8.GetBytes(url2.AbsoluteUri))).Replace("-", string.Empty).ToLowerInvariant();
			return Path.Combine(Path.GetFullPath(cacheRoot), "logos", text + ".png");
		}

		internal static byte[] ReadLogoBytes(string path)
		{
			using FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
			long length = fileStream.Length;
			if (length > 8388608)
			{
				throw new InvalidDataException("The logo exceeds the byte limit.");
			}
			byte[] array = new byte[checked((int)length)];
			int num;
			for (int i = 0; i < array.Length; i += num)
			{
				num = fileStream.Read(array, i, array.Length - i);
				if (num == 0)
				{
					throw new EndOfStreamException("The logo file is incomplete.");
				}
			}
			if (fileStream.ReadByte() != -1 || !TryValidatePng(array, out int _, out int _, out string _))
			{
				throw new InvalidDataException("The logo file is not a valid bounded PNG.");
			}
			return array;
		}

		internal static void WriteLogoCache(string path, byte[] data)
		{
			if (!TryValidatePng(data, out int _, out int _, out string rejection))
			{
				throw new InvalidDataException(rejection);
			}
			string? path2 = Path.GetDirectoryName(path) ?? throw new InvalidDataException("Invalid logo cache path.");
			Directory.CreateDirectory(path2);
			if ((File.GetAttributes(path2) & FileAttributes.ReparsePoint) != FileAttributes.None || (File.Exists(path) && (File.GetAttributes(path) & FileAttributes.ReparsePoint) != FileAttributes.None))
			{
				throw new InvalidDataException("The logo cache must use regular files and directories.");
			}
			string text = path + "." + Guid.NewGuid().ToString("N") + ".tmp";
			bool flag = false;
			try
			{
				using (FileStream fileStream = new FileStream(text, FileMode.CreateNew, FileAccess.Write, FileShare.None))
				{
					flag = true;
					fileStream.Write(data, 0, data.Length);
					fileStream.Flush(flushToDisk: true);
				}
				if (File.Exists(path))
				{
					File.Replace(text, path, null);
				}
				else
				{
					File.Move(text, path);
				}
				flag = false;
			}
			finally
			{
				if (flag)
				{
					try
					{
						File.Delete(text);
					}
					catch (IOException)
					{
					}
					catch (UnauthorizedAccessException)
					{
					}
				}
			}
		}

		internal static bool TryResolveLogoPath(string? bepinexRoot, string? relativePath, out string fullPath, out string rejection)
		{
			fullPath = string.Empty;
			rejection = string.Empty;
			string text = bepinexRoot?.Trim() ?? string.Empty;
			string text2 = relativePath?.Trim() ?? string.Empty;
			if (text.Length == 0)
			{
				rejection = "The BepInEx root is unavailable.";
				return false;
			}
			if (text2.Length == 0)
			{
				rejection = "Logo Path is empty.";
				return false;
			}
			if (Path.IsPathRooted(text2) || text2.IndexOf(':') >= 0)
			{
				rejection = "Logo Path must be relative to the BepInEx directory.";
				return false;
			}
			if (!string.Equals(Path.GetExtension(text2), ".png", StringComparison.OrdinalIgnoreCase))
			{
				rejection = "Logo Path must name a PNG file.";
				return false;
			}
			try
			{
				string text3 = Path.GetFullPath(text).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
				string fullPath2 = Path.GetFullPath(Path.Combine(text3, text2));
				char directorySeparatorChar = Path.DirectorySeparatorChar;
				string value = text3 + directorySeparatorChar;
				StringComparison comparisonType = ((Path.DirectorySeparatorChar == '\\') ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
				if (!fullPath2.StartsWith(value, comparisonType))
				{
					rejection = "Logo Path may not leave the BepInEx directory.";
					return false;
				}
				fullPath = fullPath2;
				return true;
			}
			catch (Exception ex) when (ex is ArgumentException || ex is NotSupportedException || ex is PathTooLongException)
			{
				rejection = "Logo Path is invalid: " + ex.Message;
				return false;
			}
		}

		internal static bool TryValidatePng(byte[]? data, out int width, out int height, out string rejection)
		{
			width = 0;
			height = 0;
			rejection = string.Empty;
			if (data == null || data.Length < 33)
			{
				rejection = "The logo is not a complete PNG file.";
				return false;
			}
			if (data.Length > 8388608)
			{
				rejection = $"The logo exceeds the {8388608} byte limit.";
				return false;
			}
			byte[] array = new byte[8] { 137, 80, 78, 71, 13, 10, 26, 10 };
			for (int i = 0; i < array.Length; i++)
			{
				if (data[i] != array[i])
				{
					rejection = "The logo does not have a valid PNG signature.";
					return false;
				}
			}
			if (ReadBigEndianUInt32(data, 8) != 13 || data[12] != 73 || data[13] != 72 || data[14] != 68 || data[15] != 82)
			{
				rejection = "The logo PNG does not begin with a valid IHDR chunk.";
				return false;
			}
			uint num = ReadBigEndianUInt32(data, 16);
			uint num2 = ReadBigEndianUInt32(data, 20);
			if (num == 0 || num2 == 0 || num > 4096 || num2 > 4096 || (long)num * (long)num2 > 16777216)
			{
				rejection = $"The logo dimensions must be between 1 and {4096} pixels " + "and remain within the decoded pixel limit.";
				return false;
			}
			width = (int)num;
			height = (int)num2;
			return true;
		}

		internal static void OnSetupGui(FejdStartup startup)
		{
			if (CanUseClientUi(startup))
			{
				ObserveStartup(startup);
				RefreshMenuCompatibility(startup);
				ResetMenuGuide();
				UpdateMenuGuide(startup);
				ApplyLogo(startup);
				if (TryGetConfiguredEndpoint(out var _))
				{
					ApplyMainButtonText(startup);
				}
			}
		}

		internal static void BeforeMainStart(FejdStartup startup)
		{
			CancelFlow(clearConnectionPassword: true);
			if (CanUseClientUi(startup) && !IsAltBypassPressed() && !HasQueuedJoinOrCannotInspect(startup) && TryGetConfiguredEndpoint(out var _))
			{
				_armed = true;
			}
		}

		internal static void AfterMainStart(FejdStartup startup)
		{
			if (CanUseClientUi(startup))
			{
				ObserveStartup(startup);
				ApplyCharacterButtonText(startup);
			}
		}

		internal static void AfterCharacterListUpdated(FejdStartup startup)
		{
			if (CanUseClientUi(startup))
			{
				ObserveStartup(startup);
				ApplyCharacterButtonText(startup);
			}
		}

		internal static void OnUiUpdate(FejdStartup startup)
		{
			if (CanUseClientUi(startup))
			{
				RefreshMenuCompatibility(startup);
			}
			UpdateMenuGuide(startup);
			TickRemoteLogo(startup);
			if (_armed && CanUseClientUi(startup) && HasQueuedJoinOrCannotInspect(startup))
			{
				CancelFlow(clearConnectionPassword: true);
				ApplyCharacterButtonText(startup);
			}
		}

		internal static void BeforeCharacterStart(FejdStartup startup)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			if (!_armed)
			{
				return;
			}
			if (!CanUseClientUi(startup) || IsAltBypassPressed() || HasQueuedJoinOrCannotInspect(startup) || !TryGetConfiguredEndpoint(out var destination))
			{
				CancelFlow(clearConnectionPassword: true);
				ApplyCharacterButtonText(startup);
				return;
			}
			string pendingPassword = ServerManagerPlugin.BrandingServerPassword?.Value ?? string.Empty;
			if (!TrySetQueuedJoinServer(startup, destination))
			{
				CancelFlow(clearConnectionPassword: true);
				ApplyCharacterButtonText(startup);
				return;
			}
			_pendingPassword = pendingPassword;
			_passwordAwaitingHandshake = true;
			_brandedJoinDispatched = false;
			_armed = false;
			RestoreLabel(ref _characterButtonLabel);
		}

		internal static void AfterCharacterStart(FejdStartup startup)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			if (_passwordAwaitingHandshake && !_brandedJoinDispatched)
			{
				TrySetQueuedJoinServer(startup, ServerJoinData.None);
				ClearConnectionPasswordState();
			}
		}

		internal static void BeforeTransitionToMainScene(FejdStartup startup)
		{
			if (_passwordAwaitingHandshake && _startup == startup)
			{
				_brandedJoinDispatched = true;
			}
		}

		internal static void AfterCharacterSelectionBack(FejdStartup startup)
		{
			CancelFlow(clearConnectionPassword: true);
			if (CanUseClientUi(startup))
			{
				ApplyCharacterButtonText(startup);
			}
		}

		internal static void AfterLanguageChanged(FejdStartup startup)
		{
			if (CanUseClientUi(startup))
			{
				ObserveStartup(startup);
				UpdateMenuGuide(startup, refreshText: true);
				if (TryGetConfiguredEndpoint(out var _))
				{
					ApplyMainButtonText(startup);
				}
				ApplyCharacterButtonText(startup);
			}
		}

		internal static void BeforeClientHandshake(ZNet znet)
		{
			if (!((Object)(object)znet == (Object)null) && !znet.IsServer() && _passwordAwaitingHandshake && _brandedJoinDispatched)
			{
				string text = ((_pendingPassword.Length == 0) ? null : _pendingPassword);
				if (!TryGetServerPassword(out string password) || !TrySetServerPassword(text))
				{
					ClearConnectionPasswordState();
					return;
				}
				_previousPassword = password;
				_ownedPassword = text;
				_passwordWasOverridden = true;
			}
		}

		internal static void AfterClientHandshake(ZNet znet)
		{
			if ((Object)(object)znet != (Object)null && !znet.IsServer())
			{
				ClearConnectionPasswordState();
			}
		}

		internal static void BeforeStartupDestroyed(FejdStartup startup)
		{
			if (_startup == startup)
			{
				ResetMenuGuide();
				_armed = false;
				if (!_brandedJoinDispatched)
				{
					ClearConnectionPasswordState();
				}
				else
				{
					ClearOwnedPassword();
				}
				RestoreLabel(ref _mainButtonLabel);
				RestoreLabel(ref _characterButtonLabel);
				ReleaseCustomLogo(restoreVanilla: true);
				_startup = null;
			}
		}

		internal static void OnConnectionError()
		{
			CancelFlow(clearConnectionPassword: true);
		}

		internal static void Shutdown()
		{
			ResetMenuGuide();
			CancelFlow(clearConnectionPassword: true);
			RestoreLabel(ref _mainButtonLabel);
			RestoreLabel(ref _characterButtonLabel);
			ReleaseCustomLogo(restoreVanilla: true);
			_startup = null;
			_lastEndpointWarning = string.Empty;
			_lastLogoWarning = string.Empty;
			_lastQueuedJoinAccessWarning = string.Empty;
			_lastServerPasswordAccessWarning = string.Empty;
			_lastLocalizationCacheAccessWarning = string.Empty;
		}

		private static bool TryParsePort(string value, out ushort port)
		{
			if (ushort.TryParse(value, out port))
			{
				return port != 0;
			}
			return false;
		}

		private static uint ReadBigEndianUInt32(byte[] data, int offset)
		{
			return (uint)((data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3]);
		}

		private static bool CanUseClientUi(FejdStartup? startup)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Invalid comparison between Unknown and I4
			if ((Object)(object)startup != (Object)null && !Application.isBatchMode)
			{
				return (int)SystemInfo.graphicsDeviceType != 4;
			}
			return false;
		}

		private static bool HasQueuedJoinOrCannotInspect(FejdStartup startup)
		{
			if (TryGetQueuedJoinServer(startup, out var queuedJoin))
			{
				return ((ServerJoinData)(ref queuedJoin)).IsValid;
			}
			return true;
		}

		private static bool TryGetQueuedJoinServer(FejdStartup startup, out ServerJoinData queuedJoin)
		{
			//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_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			queuedJoin = ServerJoinData.None;
			FieldInfo queuedJoinServerField = QueuedJoinServerField;
			if (queuedJoinServerField == null)
			{
				WarnOnce(ref _lastQueuedJoinAccessWarning, "missing", "Client branding quick-connect is disabled because Valheim's queued-join field could not be found.");
				return false;
			}
			try
			{
				if (queuedJoinServerField.GetValue(startup) is ServerJoinData val)
				{
					queuedJoin = val;
					return true;
				}
				WarnOnce(ref _lastQueuedJoinAccessWarning, "unexpected-type", "Client branding quick-connect is disabled because Valheim's queued-join field has an unexpected type.");
			}
			catch (Exception ex)
			{
				WarnOnce(ref _lastQueuedJoinAccessWarning, ex.GetType().FullName ?? ex.GetType().Name, "Client branding quick-connect could not inspect Valheim's queued destination: " + ex.Message);
			}
			return false;
		}

		private static bool TrySetQueuedJoinServer(FejdStartup startup, ServerJoinData queuedJoin)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			FieldInfo queuedJoinServerField = QueuedJoinServerField;
			if (queuedJoinServerField == null)
			{
				WarnOnce(ref _lastQueuedJoinAccessWarning, "missing", "Client branding quick-connect is disabled because Valheim's queued-join field could not be found.");
				return false;
			}
			try
			{
				queuedJoinServerField.SetValue(startup, queuedJoin);
				return true;
			}
			catch (Exception ex)
			{
				WarnOnce(ref _lastQueuedJoinAccessWarning, ex.GetType().FullName ?? ex.GetType().Name, "Client branding quick-connect could not update Valheim's queued destination: " + ex.Message);
				return false;
			}
		}

		private static bool TryGetServerPassword(out string? password)
		{
			password = null;
			PropertyInfo serverPasswordProperty = ServerPasswordProperty;
			if (serverPasswordProperty == null || !serverPasswordProperty.CanRead)
			{
				WarnOnce(ref _lastServerPasswordAccessWarning, "missing-getter", "Client branding could not locate Valheim's server-password property.");
				return false;
			}
			try
			{
				object value = serverPasswordProperty.GetValue(null, null);
				if (value == null || value is string)
				{
					password = (string)value;
					return true;
				}
				WarnOnce(ref _lastServerPasswordAccessWarning, "unexpected-type", "Client branding found an unexpected Valheim server-password type.");
			}
			catch (Exception ex)
			{
				WarnOnce(ref _lastServerPasswordAccessWarning, ex.GetType().FullName ?? ex.GetType().Name, "Client branding could not read Valheim's server password: " + ex.Message);
			}
			return false;
		}

		private static bool TrySetServerPassword(string? password)
		{
			PropertyInfo serverPasswordProperty = ServerPasswordProperty;
			if (serverPasswordProperty?.GetSetMethod(nonPublic: true) == null)
			{
				WarnOnce(ref _lastServerPasswordAccessWarning, "missing-setter", "Client branding could not locate Valheim's server-password setter.");
				return false;
			}
			try
			{
				serverPasswordProperty.SetValue(null, password, null);
				return true;
			}
			catch (Exception ex)
			{
				WarnOnce(ref _lastServerPasswordAccessWarning, ex.GetType().FullName ?? ex.GetType().Name, "Client branding could not update Valheim's server password: " + ex.Message);
				return false;
			}
		}

		internal static bool TryGetLocalizationTextMeshStrings(Localization localization, out Dictionary<TMP_Text, string> textMeshStrings)
		{
			textMeshStrings = null;
			FieldInfo localizationTextMeshStringsField = LocalizationTextMeshStringsField;
			if (localizationTextMeshStringsField == null)
			{
				WarnOnce(ref _lastLocalizationCacheAccessWarning, "missing", "Client branding could not locate Valheim's TMP localization cache.");
				return false;
			}
			try
			{
				if (localizationTextMeshStringsField.GetValue(localization) is Dictionary<TMP_Text, string> dictionary)
				{
					textMeshStrings = dictionary;
					return true;
				}
				WarnOnce(ref _lastLocalizationCacheAccessWarning, "unexpected-type", "Client branding found an unexpected TMP localization-cache type.");
			}
			catch (Exception ex)
			{
				WarnOnce(ref _lastLocalizationCacheAccessWarning, ex.GetType().FullName ?? ex.GetType().Name, "Client branding could not inspect Valheim's TMP localization cache: " + ex.Message);
			}
			return false;
		}

		private static bool IsAltBypassPressed()
		{
			if (!ZInput.GetKey((KeyCode)308, true))
			{
				return ZInput.GetKey((KeyCode)307, true);
			}
			return true;
		}

		internal static bool TryCreateJoinDestination(string? value, out ServerJoinData destination, out string rejection)
		{
			//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_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			destination = ServerJoinData.None;
			if (value != null && value.Trim().StartsWith("steam:", StringComparison.OrdinalIgnoreCase))
			{
				rejection = "Use steam:<host Steam64 ID> for a Steam local-host server.";
				if (!OptionalModLobbyQuery.TryParseHostEndpoint(value, out var host))
				{
					return false;
				}
				destination = new ServerJoinData(new ServerJoinDataSteamUser(host));
				rejection = string.Empty;
				return true;
			}
			if (!TryParseDedicatedEndpoint(value, out string host2, out ushort port, out rejection))
			{
				return false;
			}
			destination = new ServerJoinData(new ServerJoinDataDedicated(host2, port));
			return true;
		}

		private static bool TryGetConfiguredEndpoint(out ServerJoinData destination)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			string text = ServerManagerPlugin.BrandingServerAddress?.Value ?? string.Empty;
			if (string.IsNullOrWhiteSpace(text))
			{
				destination = ServerJoinData.None;
				_lastEndpointWarning = string.Empty;
				return false;
			}
			if (TryCreateJoinDestination(text, out destination, out string rejection))
			{
				_lastEndpointWarning = string.Empty;
				return true;
			}
			WarnOnce(ref _lastEndpointWarning, text + "\n" + rejection, "Client branding quick-connect is disabled for this menu session: " + rejection);
			return false;
		}

		private static void ObserveStartup(FejdStartup startup)
		{
			if (_startup != startup)
			{
				ResetMenuGuide();
				CancelFlow(clearConnectionPassword: true);
				RestoreLabel(ref _mainButtonLabel);
				RestoreLabel(ref _characterButtonLabel);
				ReleaseCustomLogo(restoreVanilla: true);
				_startup = startup;
			}
		}

		private static void ApplyMainButtonText(FejdStartup startup)
		{
			TMP_Text val = FindMainStartButtonText(startup);
			string configuredButtonText = GetConfiguredButtonText();
			if (!((Object)(object)val == (Object)null) && configuredButtonText.Length != 0)
			{
				ApplyLabel(ref _mainButtonLabel, val, configuredButtonText);
			}
		}

		private static void ApplyCharacterButtonText(FejdStartup startup)
		{
			TMP_Text val = (((Object)(object)startup.m_csStartButton == (Object)null) ? null : ((Component)startup.m_csStartButton).GetComponentInChildren<TMP_Text>(true));
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			if (_armed)
			{
				string configuredButtonText = GetConfiguredButtonText();
				if (configuredButtonText.Length != 0)
				{
					ApplyLabel(ref _characterButtonLabel, val, configuredButtonText);
				}
			}
			else
			{
				RestoreLabel(ref _characterButtonLabel);
			}
		}

		private static TMP_Text? FindMainStartButtonText(FejdStartup startup)
		{
			if (_mainButtonLabel != null)
			{
				return _mainButtonLabel.Text;
			}
			if ((Object)(object)startup.m_menuList == (Object)null)
			{
				return null;
			}
			Button[] componentsInChildren = startup.m_menuList.GetComponentsInChildren<Button>(true);
			Button val = ((componentsInChildren.Length != 0) ? componentsInChildren[0] : null);
			Button[] array = componentsInChildren;
			foreach (Button val2 in array)
			{
				int persistentEventCount = ((UnityEventBase)val2.onClick).GetPersistentEventCount();
				for (int j = 0; j < persistentEventCount; j++)
				{
					if (string.Equals(((UnityEventBase)val2.onClick).GetPersistentMethodName(j), "OnStartGame", StringComparison.Ordinal))
					{
						return ((Component)val2).GetComponentInChildren<TMP_Text>(true);
					}
				}
			}
			if (!((Object)(object)val == (Object)null))
			{
				return ((Component)val).GetComponentInChildren<TMP_Text>(true);
			}
			return null;
		}

		private static string GetConfiguredButtonText()
		{
			string text = ServerManagerPlugin.BrandingButtonText?.Value?.Trim() ?? string.Empty;
			if (text.Length > 128)
			{
				return text.Substring(0, 128);
			}
			return text;
		}

		private static void ApplyLabel(ref LabelOverride? current, TMP_Text text, string label)
		{
			if (current == null || current.Text != text)
			{
				RestoreLabel(ref current);
				current = new LabelOverride(text);
			}
			if (!current.LocalizationDetached)
			{
				Localization instance = Localization.instance;
				if (instance != null)
				{
					instance.RemoveTextFromCache(text);
					current.LocalizationDetached = true;
				}
			}
			ConfigureLabelForLongText(text);
			text.text = label;
		}

		private static void ConfigureLabelForLongText(TMP_Text text)
		{
			text.enableAutoSizing = true;
			text.textWrappingMode = (TextWrappingModes)0;
			text.fontSizeMin = Mathf.Min((text.fontSizeMin > 0f) ? text.fontSizeMin : 12f, 12f);
			text.fontSizeMax = Mathf.Max(text.fontSizeMax, text.fontSize);
		}

		private static void RestoreLabel(ref LabelOverride? current)
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			LabelOverride labelOverride = current;
			current = null;
			if (labelOverride != null && !((Object)(object)labelOverride.Text == (Object)null))
			{
				TMP_Text text = labelOverride.Text;
				Localization instance = Localization.instance;
				if (labelOverride.LocalizationDetached && labelOverride.HadLocalizationSource && labelOverride.LocalizationSource != null && instance != null && TryGetLocalizationTextMeshStrings(instance, out Dictionary<TMP_Text, string> textMeshStrings))
				{
					textMeshStrings[text] = labelOverride.LocalizationSource;
					text.text = instance.Localize(labelOverride.LocalizationSource);
				}
				else
				{
					text.text = labelOverride.OriginalText;
				}
				text.enableAutoSizing = labelOverride.OriginalEnableAutoSizing;
				text.textWrappingMode = labelOverride.OriginalWrappingMode;
				text.fontSizeMin = labelOverride.OriginalFontSizeMin;
				text.fontSizeMax = labelOverride.OriginalFontSizeMax;
			}
		}

		private static void ApplyLogo(FejdStartup startup)
		{
			if (_customMenuActive)
			{
				ReleaseCustomLogo(restoreVanilla: true);
				return;
			}
			GameObject mainMenu = startup.m_mainMenu;
			Transform val = ((mainMenu != null) ? mainMenu.transform.Find("Logo/LOGO") : null);
			Image val2 = (((Object)(object)val == (Object)null) ? null : ((Component)val).GetComponent<Image>());
			if ((Object)(object)val2 == (Object)null)
			{
				WarnOnce(ref _lastLogoWarning, "missing-logo-image", "Client branding could not find the vanilla Logo/LOGO image; the vanilla logo was retained.");
				return;
			}
			string text = ServerManagerPlugin.BrandingLogoPath?.Value ?? string.Empty;
			if (_logoImage != val2 || !string.Equals(_logoSource, text, StringComparison.Ordinal))
			{
				ReleaseCustomLogo(restoreVanilla: true);
				_logoImage = val2;
				_vanillaLogo = val2.sprite;
				_vanillaLogoPreserveAspect = val2.preserveAspect;
				_logoSource = text;
			}
			if (string.IsNullOrWhiteSpace(text))
			{
				return;
			}
			string bepInExRootPath = Paths.BepInExRootPath;
			if (text.IndexOf("://", StringComparison.Ordinal) >= 0)
			{
				if (!TryParseLogoUrl(text, out Uri url, out string rejection))
				{
					WarnOnce(ref _lastLogoWarning, "invalid-logo-url", rejection);
				}
				else
				{
					if (string.Equals(_remoteLogoAttemptedSource, text, StringComparison.Ordinal))
					{
						return;
					}
					CancelRemoteLogo();
					_remoteLogoAttemptedSource = text;
					string text2 = null;
					try
					{
						text2 = GetLogoCachePath(Path.Combine(ServerDataRoot.ResolveCurrentPath(), "cache"), url);
						if (File.Exists(text2))
						{
							ApplyLogoBytes(val2, ReadLogoBytes(text2));
						}
					}
					catch (Exception exception) when (!IntegrityCanonical.IsFatal(exception))
					{
						WarnOnce(ref _lastLogoWarning, "logo-cache-read", "The cached menu logo was unavailable; trying HTTPS.");
					}
					_remoteLogoLoad = new RemoteLogoLoad(startup, val2, text, url, text2);
				}
				return;
			}
			if (!TryResolveLogoPath(bepInExRootPath, text, out string fullPath, out string rejection2))
			{
				WarnOnce(ref _lastLogoWarning, text + "\n" + rejection2, "Client branding retained the vanilla logo: " + rejection2);
				return;
			}
			try
			{
				ApplyLogoBytes(val2, ReadLogoBytes(fullPath));
			}
			catch (Exception ex) when (!IntegrityCanonical.IsFatal(ex))
			{
				WarnOnce(ref _lastLogoWarning, fullPath + "\n" + ex.GetType().FullName + "\n" + ex.Message, "Client branding retained the vanilla logo: " + ex.Message);
			}
		}

		private static void TickRemoteLogo(FejdStartup startup)
		{
			RemoteLogoLoad remoteLogoLoad = _remoteLogoLoad;
			if (remoteLogoLoad == null)
			{
				return;
			}
			if (remoteLogoLoad.Startup != startup || _startup != startup || remoteLogoLoad.Image != _logoImage || (Object)(object)remoteLogoLoad.Image == (Object)null || !CanUseClientUi(startup) || !string.Equals(remoteLogoLoad.Source, ServerManagerPlugin.BrandingLogoPath?.Value, StringComparison.Ordinal))
			{
				CancelRemoteLogo();
			}
			else
			{
				if (!remoteLogoLoad.Download.IsCompleted)
				{
					return;
				}
				_remoteLogoLoad = null;
				remoteLogoLoad.Stop.Dispose();
				byte[] result;
				try
				{
					result = remoteLogoLoad.Download.GetAwaiter().GetResult();
				}
				catch (Exception exception) when (!IntegrityCanonical.IsFatal(exception))
				{
					WarnOnce(ref _lastLogoWarning, "logo-download-failed", LogoDownloadFailureMessage(exception));
					return;
				}
				try
				{
					ApplyLogoBytes(remoteLogoLoad.Image, result);
				}
				catch (Exception exception2) when (!IntegrityCanonical.IsFatal(exception2))
				{
					WarnOnce(ref _lastLogoWarning, "logo-decode-failed", "The HTTPS menu logo failed during Unity PNG decode/apply; keeping the cached or vanilla logo.");
					return;
				}
				if (remoteLogoLoad.CachePath != null)
				{
					try
					{
						WriteLogoCache(remoteLogoLoad.CachePath, result);
					}
					catch (Exception exception3) when (!IntegrityCanonical.IsFatal(exception3))
					{
						WarnOnce(ref _lastLogoWarning, "logo-cache-write", "The HTTPS menu logo was applied, but its cache could not be saved.");
					}
				}
			}
		}

		private static void CancelRemoteLogo()
		{
			RemoteLogoLoad load = _remoteLogoLoad;
			_remoteLogoLoad = null;
			if (load == null)
			{
				return;
			}
			load.Stop.Cancel();
			load.Download.ContinueWith(delegate(Task<byte[]> completed)
			{
				if (completed.IsFaulted)
				{
					_ = completed.Exception;
				}
				load.Stop.Dispose();
			}, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
		}

		private static void ApplyLogoBytes(Image image, byte[] data)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Expected O, but got Unknown
			//IL_006e: 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)
			Texture2D val = null;
			Sprite val2 = null;
			try
			{
				if (!TryValidatePng(data, out int width, out int height, out string rejection))
				{
					throw new InvalidDataException(rejection);
				}
				val = new Texture2D(2, 2, (TextureFormat)4, false)
				{
					name = "ServerManager.ClientMenuLogo"
				};
				if (!TryLoadPng(val, data) || ((Texture)val).width != width || ((Texture)val).height != height)
				{
					throw new InvalidDataException("Unity could not decode the validated PNG dimensions.");
				}
				val2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
				((Object)val2).name = "ServerManager.ClientMenuLogo";
				Sprite? customLogo = _customLogo;
				Texture2D customLogoTexture = _customLogoTexture;
				image.preserveAspect = true;
				image.sprite = val2;
				_customLogo = val2;
				_customLogoTexture = val;
				val2 = null;
				val = null;
				DestroyCustomLogo(customLogo, customLogoTexture);
				_lastLogoWarning = string.Empty;
				ServerManagerPlugin.Log.LogInfo((object)$"Applied client menu logo ({width}x{height}).");
			}
			finally
			{
				DestroyCustomLogo(val2, val);
			}
		}

		private static void ReleaseCustomLogo(bool restoreVanilla)
		{
			CancelRemoteLogo();
			_remoteLogoAttemptedSource = null;
			_logoSource = null;
			if (restoreVanilla && (Object)(object)_logoImage != (Object)null && (Object)(object)_customLogo != (Object)null && _logoImage.sprite == _customLogo)
			{
				_logoImage.sprite = _vanillaLogo;
				_logoImage.preserveAspect = _vanillaLogoPreserveAspect;
			}
			DestroyCustomLogo(_customLogo, _customLogoTexture);
			_customLogo = null;
			_customLogoTexture = null;
			_logoImage = null;
			_vanillaLogo = null;
			_vanillaLogoPreserveAspect = false;
		}

		private static bool TryLoadPng(Texture2D texture, byte[] data)
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(ImageConversion), "LoadImage", new Type[3]
			{
				typeof(Texture2D),
				typeof(byte[]),
				typeof(bool)
			}, (Type[])null);
			if (methodInfo == null)
			{
				return false;
			}
			object obj = methodInfo.Invoke(null, new object[3] { texture, data, true });
			bool flag = default(bool);
			int num;
			if (obj is bool)
			{
				flag = (bool)obj;
				num = 1;
			}
			else
			{
				num = 0;
			}
			return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		}

		private static void DestroyCustomLogo(Sprite? sprite, Texture2D? texture)
		{
			if ((Object)(object)sprite != (Object)null)
			{
				Object.Destroy((Object)(object)sprite);
			}
			if ((Object)(object)texture != (Object)null)
			{
				Object.Destroy((Object)(object)texture);
			}
		}

		private static void CancelFlow(bool clearConnectionPassword)
		{
			_armed = false;
			if (clearConnectionPassword)
			{
				ClearConnectionPasswordState();
			}
		}

		private static void ClearConnectionPasswordState()
		{
			ClearOwnedPassword();
			_pendingPassword = string.Empty;
			_passwordAwaitingHandshake = false;
			_brandedJoinDispatched = false;
		}

		private static void ClearOwnedPassword()
		{
			if (_passwordWasOverridden && TryGetServerPassword(out string password) && string.Equals(password, _ownedPassword, StringComparison.Ordinal))
			{
				TrySetServerPassword(_previousPassword);
			}
			_ownedPassword = null;
			_previousPassword = null;
			_passwordWasOverridden = false;
		}

		private static void WarnOnce(ref string previousKey, string key, string message)
		{
			if (!string.Equals(previousKey, key, StringComparison.Ordinal))
			{
				previousKey = key;
				ServerManagerPlugin.Log.LogWarning((object)message);
			}
		}
	}
	[HarmonyPatch(typeof(FejdStartup), "SetupGui")]
	internal static class ClientMenuBrandingSetupGuiPatch
	{
		[HarmonyPriority(0)]
		private static void Postfix(FejdStartup __instance)
		{
			ClientMenuBranding.OnSetupGui(__instance);
		}
	}
	[HarmonyPatch(typeof(FejdStartup), "Update")]
	internal static class ClientMenuBrandingUiUpdatePatch
	{
		[HarmonyPriority(800)]
		private static bool Prefix()
		{
			return ClientMenuBranding.BeforeUiUpdate();
		}

		private static void Postfix(FejdStartup __instance)
		{
			ClientMenuBranding.OnUiUpdate(__instance);
		}
	}
	[HarmonyPatch(typeof(FejdStartup), "OnStartGame")]
	internal static class ClientMenuBrandingMainStartPatch
	{
		private static void Prefix(FejdStartup __instance)
		{
			ClientMenuBranding.BeforeMainStart(__instance);
		}

		private static void Postfix(FejdStartup __instance)
		{
			ClientMenuBranding.AfterMainStart(__instance);
		}
	}
	[HarmonyPatch(typeof(FejdStartup), "UpdateCharacterList")]
	internal static class ClientMenuBrandingCharacterListPatch
	{
		private static void Postfix(FejdStartup __instance)
		{
			ClientMenuBranding.AfterCharacterListUpdated(__instance);
		}
	}
	[HarmonyPatch(typeof(FejdStartup), "OnCharacterStart")]
	internal static class ClientMenuBrandingCharacterStartPatch
	{
		[HarmonyPriority(0)]
		private static void Prefix(FejdStartup __instance)
		{
			ClientMenuBranding.BeforeCharacterStart(__instance);
		}

		private static Exception? Finalizer(FejdStartup __instance, Exception? __exception)
		{
			ClientMenuBranding.AfterCharacterStart(__instance);
			return __exception;
		}
	}
	[HarmonyPatch(typeof(FejdStartup), "TransitionToMainScene")]
	internal static class ClientMenuBrandingTransitionPatch
	{
		private static void Prefix(FejdStartup __instance)
		{
			ClientMenuBranding.BeforeTransitionToMainScene(__instance);
		}
	}
	[HarmonyPatch(typeof(FejdStartup), "OnSelelectCharacterBack")]
	internal static class ClientMenuBrandingCharacterBackPatch
	{
		private static void Postfix(FejdStartup __instance)
		{
			ClientMenuBranding.AfterCharacterSelectionBack(__instance);
		}
	}
	[HarmonyPatch(typeof(FejdStartup), "OnLanguageChange")]
	internal static class ClientMenuBrandingLanguagePatch
	{
		private static void Postfix(FejdStartup __instance)
		{
			ClientMenuBranding.AfterLanguageChanged(__instance);
		}
	}
	[HarmonyPatch(typeof(ZNet), "RPC_ClientHandshake")]
	internal static class ClientMenuBrandingPasswordCleanupPatch
	{
		private static void Prefix(ZNet __instance)
		{
			ClientMenuBranding.BeforeClientHandshake(__instance);
		}

		private static Exception? Finalizer(ZNet __instance, Exception? __exception)
		{
			ClientMenuBranding.AfterClientHandshake(__instance);
			return __exception;
		}
	}
	[BepInPlugin("sighsorry.ServerManager", "ServerManager", "1.0.9")]
	[BepInIncompatibility("Azumatt.MaxPlayerCount")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public sealed class ServerManagerPlugin : BaseUnityPlugin
	{
		private sealed class ConfigurationManagerAttributes
		{
			public int? Order;
		}

		internal const string ModName = "ServerManager";

		internal const string ModVersion = "1.0.9";

		internal const string Author = "sighsorry";

		internal const string ModGuid = "sighsorry.ServerManager";

		internal const bool DefaultEnforceModPolicy = true;

		private readonly Harmony _harmony = new Harmony("sighsorry.ServerManager");

		private bool _shuttingDown;

		private bool _quitHandlerRegistered;

		internal static ManualLogSource Log { get; private set; } = null;

		internal static string ConnectionError { get; set; } = string.Empty;