Decompiled source of CustomMainMenu v1.3.0

plugins/CustomMainMenu.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.Rendering;
using UnityEngine.UI;
using Valheim.SettingsGui;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("CustomMainMenu")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Custom main menu logo, music, loading art, Discord link, and optional skip of the 1.0 startup intro.")]
[assembly: AssemblyFileVersion("1.3.0.0")]
[assembly: AssemblyInformationalVersion("1.3.0")]
[assembly: AssemblyProduct("CustomMainMenu")]
[assembly: AssemblyTitle("CustomMainMenu")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.3.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace CustomMainMenu
{
	internal static class ConfigLayout
	{
		internal static readonly string[] SectionOrder = new string[5] { "General", "Startup", "Main Menu", "Changelog", "Discord Panel" };

		internal static bool IsOurs(ConfigFile config)
		{
			if ((Object)(object)CustomMainMenuPlugin.Instance != (Object)null)
			{
				return config == ((BaseUnityPlugin)CustomMainMenuPlugin.Instance).Config;
			}
			return false;
		}

		internal static void Write(ConfigFile config)
		{
			Dictionary<string, List<ConfigEntryBase>> dictionary = new Dictionary<string, List<ConfigEntryBase>>(StringComparer.Ordinal);
			foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in config)
			{
				if (!dictionary.TryGetValue(item.Key.Section, out var value))
				{
					value = new List<ConfigEntryBase>();
					dictionary[item.Key.Section] = value;
				}
				value.Add(item.Value);
			}
			string configFilePath = config.ConfigFilePath;
			string directoryName = Path.GetDirectoryName(configFilePath);
			if (!string.IsNullOrEmpty(directoryName))
			{
				Directory.CreateDirectory(directoryName);
			}
			using StreamWriter streamWriter = new StreamWriter(configFilePath, append: false, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
			streamWriter.NewLine = "\r\n";
			streamWriter.WriteLine("## Settings file was created by plugin Custom Main Menu v1.3.0");
			streamWriter.WriteLine("## Plugin GUID: rdmods.custommainmenu");
			streamWriter.WriteLine();
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			for (int i = 0; i < SectionOrder.Length; i++)
			{
				string text = SectionOrder[i];
				if (dictionary.TryGetValue(text, out var value2))
				{
					WriteSection(streamWriter, text, value2);
					hashSet.Add(text);
				}
			}
			foreach (KeyValuePair<string, List<ConfigEntryBase>> item2 in dictionary)
			{
				if (!hashSet.Contains(item2.Key))
				{
					WriteSection(streamWriter, item2.Key, item2.Value);
				}
			}
		}

		private static void WriteSection(StreamWriter writer, string section, List<ConfigEntryBase> entries)
		{
			writer.WriteLine("[" + section + "]");
			writer.WriteLine();
			for (int i = 0; i < entries.Count; i++)
			{
				ConfigEntryBase val = entries[i];
				val.WriteDescription(writer);
				writer.WriteLine(val.Definition.Key + " = " + val.GetSerializedValue());
				writer.WriteLine();
			}
		}
	}
	internal static class Hu
	{
		internal const string StartGameLower = "játék indítása";

		internal const string SettingsLower = "beállitások";

		internal const string PatchNotesTitleLower = "frissítési napló";

		internal const string ModdedMarkerLower = "módosított";
	}
	[BepInPlugin("rdmods.custommainmenu", "Custom Main Menu", "1.3.0")]
	public sealed class CustomMainMenuPlugin : BaseUnityPlugin
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static UnityAction <0>__OnDiscordJoinClicked;
		}

		public const string ModGuid = "rdmods.custommainmenu";

		public const string ModName = "Custom Main Menu";

		public const string ModVersion = "1.3.0";

		public const string AssetFolderName = "CustomMainMenu";

		public const string LoadingArtFolderName = "LoadingArt";

		public const string PluginDefaultsFolderName = "defaults";

		public const string HowToCustomizeFileName = "README-HOW-TO-CUSTOMIZE.txt";

		public const int LoadingArtMaxSlot = 12;

		public const string DiscordTitleText = "Need help? Join Discord!";

		public const string DiscordButtonText = "Click here to join Discord!";

		internal const float MenuMusicBaseGain = 0.72f;

		internal static bool MenuMusicFadeCommittedForSession;

		internal static volatile bool MainMenuActive;

		internal static readonly bool EnableCustomLoadingScreens = true;

		private ConfigEntry<bool>? _enableLogging;

		private Harmony? _harmony;

		private GameObject? _menuMusicGo;

		private AudioSource? _menuMusicSource;

		private Coroutine? _menuMusicFadeCoroutine;

		private Coroutine? _menuMusicStartCoroutine;

		private Coroutine? _menuAtmosphereApplyCoroutine;

		private bool _menuMusicPausedForCinematic;

		private float _menuMusicFadeFactor = 1f;

		private static GameObject? _discordPanel;

		private static GameObject? _discordJoinButton;

		private Coroutine? _discordLogoCoroutine;

		private static Image? _discordLogoImage;

		private static TMP_FontAsset? _cachedDiscordFont;

		private static string? _pluginDefaultsRoot;

		private static string? _loadingArtSourceFolder;

		private static bool _loadingArtSourceResolved;

		private static readonly string[] ImageExtensions = new string[3] { ".png", ".jpg", ".jpeg" };

		private static readonly HashSet<string> NeverHide = new HashSet<string>(StringComparer.Ordinal)
		{
			"startgui", "worldpanel", "startgame", "topleft", "topright", "menu", "joinpanel", "panel", "tooltips", "eula",
			"eulawindow", "showeula", "version", "versionlabel", "cinematics", "cinematicslist"
		};

		internal static CustomMainMenuPlugin? Instance { get; private set; }

		internal static ConfigEntry<bool>? ModEnabled { get; private set; }

		internal static ManualLogSource? ModLog { get; private set; }

		internal static GameObject? DiscordPanelRoot => _discordPanel;

		internal static bool IsVerboseLogging
		{
			get
			{
				if (Instance?._enableLogging != null)
				{
					return Instance._enableLogging.Value;
				}
				return false;
			}
		}

		internal static void SetDiscordPanelRoot(GameObject? panel)
		{
			_discordPanel = panel;
		}

		private void Awake()
		{
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Expected O, but got Unknown
			Instance = this;
			ModLog = ((BaseUnityPlugin)this).Logger;
			MenuMusicFadeCommittedForSession = false;
			bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet;
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
			ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Turn this mod on or off.");
			_enableLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableLogging", false, "Write informational logs (menu lifecycle, loading watcher, atmosphere, Discord visibility). Delete cfg after changing.");
			SkipStartupIntro.BindConfig(((BaseUnityPlugin)this).Config);
			MenuAmbientMute.BindConfig(((BaseUnityPlugin)this).Config);
			MenuChangelog.BindConfig(((BaseUnityPlugin)this).Config);
			DiscordPanelVisibility.BindConfig(((BaseUnityPlugin)this).Config);
			ConfigLayout.Write(((BaseUnityPlugin)this).Config);
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet;
			if (!ModEnabled.Value)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Custom Main Menu is disabled in config.");
				return;
			}
			EnsureAssetDirectories();
			CachePluginDefaultsRoot();
			TryInstallHowToCustomize();
			ResolveLoadingArtSourceFolderOnce();
			MenuChangelog.Initialize();
			_harmony = new Harmony("rdmods.custommainmenu");
			ApplyHarmonyPatchesSafely(_harmony);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Custom Main Menu 1.3.0 loaded. Asset root: " + GetAssetRootPath()));
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Loading art folder: " + GetResolvedLoadingArtFolder()));
			((BaseUnityPlugin)this).Logger.LogInfo((object)SkipStartupIntro.DescribeConfig());
		}

		private void OnDestroy()
		{
			SkipStartupIntro.ResetSession();
			MenuAmbientMute.Shutdown();
			MenuChangelog.Shutdown();
			LoadingScreens.StopAllWatchers("plugin destroyed");
			if (_discordLogoCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(_discordLogoCoroutine);
				_discordLogoCoroutine = null;
			}
			if (_menuMusicFadeCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(_menuMusicFadeCoroutine);
				_menuMusicFadeCoroutine = null;
			}
			if (_menuMusicStartCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(_menuMusicStartCoroutine);
				_menuMusicStartCoroutine = null;
			}
			if (_menuAtmosphereApplyCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(_menuAtmosphereApplyCoroutine);
				_menuAtmosphereApplyCoroutine = null;
			}
			MenuAtmosphere.Clear();
			DestroyDiscordPanel();
			MainMenuActive = false;
			StopMenuMusic();
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			_harmony = null;
			Instance = null;
		}

		internal static bool TryGetLocalPlayerPresentPlain()
		{
			try
			{
				return (Object)(object)Player.m_localPlayer != (Object)null;
			}
			catch
			{
				return false;
			}
		}

		internal static void CommitMenuMusicFadeForWorldEntry(string trigger)
		{
			if (ModEnabled != null && ModEnabled.Value && !MenuMusicFadeCommittedForSession)
			{
				MenuMusicFadeCommittedForSession = true;
				LogInfo("Stopping menu music (" + trigger + ").");
				FadeOutAndStopMenuMusic();
			}
		}

		internal static bool IsWorldFullyLoaded()
		{
			bool num = TryGetLocalPlayerPresentPlain();
			if (num && !MenuMusicFadeCommittedForSession)
			{
				CommitMenuMusicFadeForWorldEntry("local player in world");
			}
			return num;
		}

		internal static void LogInfo(string message)
		{
			if (IsVerboseLogging)
			{
				ManualLogSource? modLog = ModLog;
				if (modLog != null)
				{
					modLog.LogInfo((object)message);
				}
			}
		}

		internal static void LogWarn(string message)
		{
			ManualLogSource? modLog = ModLog;
			if (modLog != null)
			{
				modLog.LogWarning((object)message);
			}
		}

		private void ApplyHarmonyPatchesSafely(Harmony harmony)
		{
			int num = 0;
			int num2 = 0;
			Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(typeof(CustomMainMenuPlugin).Assembly);
			foreach (Type type in typesFromAssembly)
			{
				num++;
				try
				{
					harmony.CreateClassProcessor(type).Patch();
				}
				catch (Exception ex)
				{
					num2++;
					((BaseUnityPlugin)this).Logger.LogError((object)("Harmony patch failed for " + type.FullName + ": " + ex.Message));
				}
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} Harmony apply finished (types={1}, failures={2}).", "Custom Main Menu", num, num2));
		}

		internal static bool HasCustomMenuMusic()
		{
			try
			{
				return File.Exists(GetMusicPath());
			}
			catch
			{
				return false;
			}
		}

		internal static string GetAssetRootPath()
		{
			return Path.Combine(Paths.ConfigPath, "CustomMainMenu");
		}

		internal static string GetLoadingArtFolder()
		{
			return Path.Combine(GetAssetRootPath(), "LoadingArt");
		}

		internal static string GetPluginDefaultsRoot()
		{
			if (_pluginDefaultsRoot != null)
			{
				return _pluginDefaultsRoot;
			}
			CachePluginDefaultsRoot();
			return _pluginDefaultsRoot ?? string.Empty;
		}

		internal static string GetResolvedLoadingArtFolder()
		{
			if (!_loadingArtSourceResolved)
			{
				ResolveLoadingArtSourceFolderOnce();
			}
			return _loadingArtSourceFolder ?? GetLoadingArtFolder();
		}

		internal static string GetLogoPath()
		{
			return ResolveUserOrDefaultImage("logo");
		}

		internal static string GetDiscordLogoPath()
		{
			return ResolveUserOrDefaultImage("discordlogo");
		}

		private static string ResolveImagePath(string folder, string baseName)
		{
			for (int i = 0; i < ImageExtensions.Length; i++)
			{
				string text = Path.Combine(folder, baseName + ImageExtensions[i]);
				if (File.Exists(text))
				{
					return text;
				}
			}
			return Path.Combine(folder, baseName + ImageExtensions[0]);
		}

		private static string ResolveUserOrDefaultImage(string baseName)
		{
			string text = ResolveImagePath(GetAssetRootPath(), baseName);
			if (File.Exists(text))
			{
				return text;
			}
			string pluginDefaultsRoot = GetPluginDefaultsRoot();
			if (string.IsNullOrEmpty(pluginDefaultsRoot))
			{
				return text;
			}
			string text2 = ResolveImagePath(pluginDefaultsRoot, baseName);
			if (!File.Exists(text2))
			{
				return text;
			}
			return text2;
		}

		private static string ResolveUserOrDefaultExact(string fileName)
		{
			string text = Path.Combine(GetAssetRootPath(), fileName);
			if (File.Exists(text))
			{
				return text;
			}
			string pluginDefaultsRoot = GetPluginDefaultsRoot();
			if (string.IsNullOrEmpty(pluginDefaultsRoot))
			{
				return text;
			}
			string text2 = Path.Combine(pluginDefaultsRoot, fileName);
			if (!File.Exists(text2))
			{
				return text;
			}
			return text2;
		}

		internal static string GetMusicPath()
		{
			return ResolveUserOrDefaultExact("mainmenu.ogg");
		}

		internal static string GetChangelogPath()
		{
			return ResolveUserOrDefaultExact("changelog.txt");
		}

		internal static string? GetRandomLoadingArtPath()
		{
			string resolvedLoadingArtFolder = GetResolvedLoadingArtFolder();
			if (!Directory.Exists(resolvedLoadingArtFolder))
			{
				return null;
			}
			string result = null;
			int num = 0;
			for (int i = 1; i <= 12; i++)
			{
				string text = ResolveImagePath(resolvedLoadingArtFolder, $"art{i}");
				if (File.Exists(text))
				{
					num++;
					if (num == 1 || Random.Range(0, num) == 0)
					{
						result = text;
					}
				}
			}
			return result;
		}

		private void EnsureAssetDirectories()
		{
			try
			{
				Directory.CreateDirectory(GetAssetRootPath());
				Directory.CreateDirectory(GetLoadingArtFolder());
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not create asset folders: " + ex.Message));
			}
		}

		private static void TryInstallHowToCustomize()
		{
			try
			{
				string pluginDefaultsRoot = GetPluginDefaultsRoot();
				if (string.IsNullOrEmpty(pluginDefaultsRoot))
				{
					return;
				}
				string text = Path.Combine(pluginDefaultsRoot, "README-HOW-TO-CUSTOMIZE.txt");
				if (File.Exists(text))
				{
					string assetRootPath = GetAssetRootPath();
					Directory.CreateDirectory(assetRootPath);
					string text2 = Path.Combine(assetRootPath, "README-HOW-TO-CUSTOMIZE.txt");
					if (!File.Exists(text2) || new FileInfo(text).Length != new FileInfo(text2).Length)
					{
						File.Copy(text, text2, overwrite: true);
					}
				}
			}
			catch (Exception ex)
			{
				LogWarn("How-to customize file could not be copied: " + ex.Message);
			}
		}

		private static void CachePluginDefaultsRoot()
		{
			try
			{
				CustomMainMenuPlugin? instance = Instance;
				string text = ((instance != null) ? ((BaseUnityPlugin)instance).Info.Location : null);
				if (string.IsNullOrEmpty(text))
				{
					_pluginDefaultsRoot = string.Empty;
					return;
				}
				string directoryName = Path.GetDirectoryName(text);
				_pluginDefaultsRoot = (string.IsNullOrEmpty(directoryName) ? string.Empty : Path.Combine(directoryName, "defaults"));
			}
			catch
			{
				_pluginDefaultsRoot = string.Empty;
			}
		}

		private static void ResolveLoadingArtSourceFolderOnce()
		{
			if (!_loadingArtSourceResolved)
			{
				_loadingArtSourceResolved = true;
				string loadingArtFolder = GetLoadingArtFolder();
				if (DirectoryHasLoadingImages(loadingArtFolder))
				{
					_loadingArtSourceFolder = loadingArtFolder;
					return;
				}
				string pluginDefaultsRoot = GetPluginDefaultsRoot();
				string text = (string.IsNullOrEmpty(pluginDefaultsRoot) ? string.Empty : Path.Combine(pluginDefaultsRoot, "LoadingArt"));
				_loadingArtSourceFolder = (DirectoryHasLoadingImages(text) ? text : loadingArtFolder);
			}
		}

		private static bool DirectoryHasLoadingImages(string dir)
		{
			if (string.IsNullOrEmpty(dir) || !Directory.Exists(dir))
			{
				return false;
			}
			try
			{
				for (int i = 0; i < ImageExtensions.Length; i++)
				{
					using IEnumerator<string> enumerator = Directory.EnumerateFiles(dir, "*" + ImageExtensions[i]).GetEnumerator();
					if (enumerator.MoveNext())
					{
						_ = enumerator.Current;
						return true;
					}
				}
			}
			catch
			{
				return false;
			}
			return false;
		}

		internal static void OnMainMenuOpened(FejdStartup fejd)
		{
			MainMenuActive = true;
			DiscordPanelVisibility.ResetSessionState();
			MenuAtmosphere.ResetForMenuSession();
			StopMusicManWorldMusicForMainMenu();
			MenuAmbientMute.Apply();
			if ((Object)(object)Instance == (Object)null)
			{
				MenuAtmosphere.Apply();
				EnsureDiscordPanel(fejd, "main menu opened");
				return;
			}
			if (Instance._menuAtmosphereApplyCoroutine != null)
			{
				((MonoBehaviour)Instance).StopCoroutine(Instance._menuAtmosphereApplyCoroutine);
				Instance._menuAtmosphereApplyCoroutine = null;
			}
			Instance._menuAtmosphereApplyCoroutine = ((MonoBehaviour)fejd).StartCoroutine(MenuAtmosphere.ApplyWhenReady());
			EnsureDiscordPanel(fejd, "main menu opened");
		}

		internal static void OnWorldLoadCommitted()
		{
			LoadingScreens.StopAllWatchers("world load committed");
			MenuAmbientMute.Restore();
			DestroyDiscordPanel();
			MenuAtmosphere.Clear();
			LogInfo("Menu atmosphere cleared (world load).");
			if (Instance?._menuAtmosphereApplyCoroutine != null)
			{
				((MonoBehaviour)Instance).StopCoroutine(Instance._menuAtmosphereApplyCoroutine);
				Instance._menuAtmosphereApplyCoroutine = null;
			}
			MainMenuActive = false;
			try
			{
				MusicMan instance = MusicMan.instance;
				if ((Object)(object)instance != (Object)null)
				{
					MusicManAccess.ReleaseMainMenuMute(instance);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource? modLog = ModLog;
				if (modLog != null)
				{
					modLog.LogError((object)ex);
				}
			}
		}

		internal static void SilenceMusicManForMainMenu()
		{
			try
			{
				MusicMan instance = MusicMan.instance;
				if (!((Object)(object)instance == (Object)null))
				{
					MusicManAccess.SilenceForMainMenu(instance);
				}
			}
			catch (Exception ex)
			{
				ManualLogSource? modLog = ModLog;
				if (modLog != null)
				{
					modLog.LogError((object)ex);
				}
			}
		}

		private static void StopMusicManWorldMusicForMainMenu()
		{
			SilenceMusicManForMainMenu();
			LogInfo("MusicMan world music cleared for main menu.");
		}

		internal static void PresentBrandedMenu(FejdStartup fejd, string reason)
		{
			LogInfo("Main menu presented (" + reason + ").");
			OnMainMenuOpened(fejd);
			ApplyMenuChrome(fejd);
			MenuChangelog.ApplyOnMenuOpen(fejd);
			StartMenuMusic();
		}

		internal static void HideTitleLogo(FejdStartup fejd)
		{
			if (!((Object)(object)fejd == (Object)null))
			{
				Transform val = FindDeepNorthLogoRoot(((Component)fejd).transform);
				if ((Object)(object)val != (Object)null && ((Component)val).gameObject.activeSelf)
				{
					((Component)val).gameObject.SetActive(false);
				}
			}
		}

		internal static void ApplyMenuChrome(FejdStartup fejd)
		{
			if (!((Object)(object)fejd == (Object)null))
			{
				HideMenuClutterOnce(fejd);
				if (!ApplyCustomLogo(fejd) && !((Object)(object)Instance == (Object)null))
				{
					((MonoBehaviour)Instance).StartCoroutine(RetryLogoNextFrame(fejd));
				}
			}
		}

		private static IEnumerator RetryLogoNextFrame(FejdStartup fejd)
		{
			yield return null;
			if (MainMenuActive && (Object)(object)fejd != (Object)null && !CinematicsManager.IsStartedPlaying())
			{
				ApplyCustomLogo(fejd);
			}
		}

		private static void HideMenuClutterOnce(FejdStartup fejd)
		{
			HideSerializedClutter(fejd);
			HideVanillaDiscordButton(fejd);
			HideNamedClutterUnder(((Object)(object)fejd.m_menuList != (Object)null) ? fejd.m_menuList.transform : null);
			HideNamedClutterUnder(((Object)(object)fejd.m_mainMenu != (Object)null) ? fejd.m_mainMenu.transform : null);
			if ((Object)(object)fejd.m_merchStoreButtonParent != (Object)null)
			{
				HideNamedClutterUnder(fejd.m_merchStoreButtonParent.transform);
			}
		}

		private static void HideSerializedClutter(FejdStartup fejd)
		{
			HideGo(fejd.m_moddedText, "m_moddedText");
			HideGo(fejd.m_merchStoreButtonParent, "m_merchStoreButtonParent");
			if (!MenuChangelog.ShouldShowPanel())
			{
				HideGo(fejd.m_changeLog, "m_changeLog");
				HideGo(fejd.m_showChangelogButton, "m_showChangelogButton");
				HideGo(fejd.m_changeLogNotice, "m_changeLogNotice");
			}
		}

		private static void HideNamedClutterUnder(Transform? root)
		{
			if (!((Object)(object)root == (Object)null))
			{
				HideNamedClutterWalk(root);
			}
		}

		private static void HideNamedClutterWalk(Transform tr)
		{
			GameObject gameObject = ((Component)tr).gameObject;
			string text = (((Object)gameObject).name ?? string.Empty).ToLowerInvariant();
			if (!NeverHide.Contains(text) && !IsProtectedMenuObject(text))
			{
				string lowerOwn = string.Empty;
				bool flag;
				switch (text)
				{
				case "topic":
				case "url":
				case "text":
				case "modded_text":
					flag = true;
					break;
				default:
					flag = false;
					break;
				}
				if (flag)
				{
					lowerOwn = GetOwnText(gameObject).ToLowerInvariant();
				}
				if (ShouldHideUi(text, lowerOwn) && gameObject.activeSelf)
				{
					gameObject.SetActive(false);
				}
			}
			for (int i = 0; i < tr.childCount; i++)
			{
				HideNamedClutterWalk(tr.GetChild(i));
			}
		}

		private static void HideVanillaDiscordButton(FejdStartup fejd)
		{
			HideVanillaDiscordUnder(fejd.m_menuList);
			if ((Object)(object)fejd.m_menuList != (Object)(object)fejd.m_mainMenu)
			{
				HideVanillaDiscordUnder(fejd.m_mainMenu);
			}
		}

		private static void HideVanillaDiscordUnder(GameObject? root)
		{
			if ((Object)(object)root == (Object)null)
			{
				return;
			}
			Button[] componentsInChildren = root.GetComponentsInChildren<Button>(true);
			foreach (Button val in componentsInChildren)
			{
				if ((Object)(object)((val != null) ? ((Component)val).gameObject : null) == (Object)null || IsOurDiscordUi(((Component)val).gameObject))
				{
					continue;
				}
				bool flag = false;
				int persistentEventCount = ((UnityEventBase)val.onClick).GetPersistentEventCount();
				for (int j = 0; j < persistentEventCount; j++)
				{
					if (string.Equals(((UnityEventBase)val.onClick).GetPersistentMethodName(j), "OnButtonDiscord", StringComparison.Ordinal))
					{
						flag = true;
						break;
					}
				}
				if ((((Object)((Component)val).gameObject).name ?? string.Empty).ToLowerInvariant().Contains("discord"))
				{
					flag = true;
				}
				if (flag)
				{
					((Component)val).gameObject.SetActive(false);
					LogInfo("Vanilla Discord control hidden (" + ((Object)((Component)val).gameObject).name + ").");
				}
			}
		}

		private static bool IsOurDiscordUi(GameObject go)
		{
			Transform val = go.transform;
			while ((Object)(object)val != (Object)null)
			{
				if (((Object)val).name == "CustomMainMenuDiscordPanel")
				{
					return true;
				}
				val = val.parent;
			}
			return false;
		}

		private static void HideGo(GameObject? go, string label)
		{
			if (!((Object)(object)go == (Object)null) && go.activeSelf)
			{
				go.SetActive(false);
				LogInfo("Hidden " + label + " (" + ((Object)go).name + ").");
			}
		}

		private static bool IsProtectedMenuObject(string lowerName)
		{
			if (!lowerName.Contains("eula") && !lowerName.Contains("cinematic"))
			{
				return lowerName.Contains("version");
			}
			return true;
		}

		private static bool ShouldHideUi(string lowerName, string lowerOwn)
		{
			if (IsProtectedMenuObject(lowerName))
			{
				return false;
			}
			bool flag;
			switch (lowerName)
			{
			case "canvas changelog":
			case "changelog":
			case "topic":
			case "patchlogscroll":
				flag = true;
				break;
			default:
				flag = false;
				break;
			}
			if (flag || lowerOwn == "frissítési napló")
			{
				return !MenuChangelog.ShouldShowPanel();
			}
			if (lowerName.Contains("merch") || lowerName == "valheim.shop" || lowerName == "url" || lowerOwn == "valheim.shop")
			{
				return true;
			}
			if (lowerName == "modded_text" || lowerOwn.Contains("currently playing a modded version") || lowerOwn.Contains("modded version") || lowerOwn.Contains("módosított"))
			{
				return true;
			}
			return false;
		}

		private static string GetOwnText(GameObject go)
		{
			TextMeshProUGUI component = go.GetComponent<TextMeshProUGUI>();
			if ((Object)(object)component != (Object)null && !string.IsNullOrWhiteSpace(((TMP_Text)component).text))
			{
				return ((TMP_Text)component).text.Trim();
			}
			Text component2 = go.GetComponent<Text>();
			if (!((Object)(object)component2 != (Object)null) || string.IsNullOrWhiteSpace(component2.text))
			{
				return string.Empty;
			}
			return component2.text.Trim();
		}

		private static bool ApplyCustomLogo(FejdStartup fejd)
		{
			Transform val = FindDeepNorthLogoRoot(((Component)fejd).transform);
			if ((Object)(object)val != (Object)null)
			{
				HideLogoVfxChildren(val);
				if (!((Component)val).gameObject.activeSelf)
				{
					((Component)val).gameObject.SetActive(true);
				}
			}
			if (!File.Exists(GetLogoPath()))
			{
				return true;
			}
			Image best = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<Image>() : null);
			int hi = (((Object)(object)best != (Object)null) ? ScoreLogo(best) : int.MinValue);
			if ((Object)(object)best == (Object)null || hi < 50)
			{
				FindBestLogoImage(((Component)fejd).transform, ref best, ref hi);
			}
			bool flag = (Object)(object)best != (Object)null && LogoLooksNamed(best);
			if ((Object)(object)best == (Object)null || (hi < 50 && !(hi >= 25 && flag)))
			{
				if (IsVerboseLogging)
				{
					LogWarn($"Logo not applied (best score {hi}). EnableLogging dumps named logo objects.");
				}
				return (Object)(object)best != (Object)null;
			}
			Sprite val2 = LoadSpriteFromDisk(GetLogoPath());
			if ((Object)(object)val2 == (Object)null)
			{
				return false;
			}
			ApplyLogo(best, val2);
			if (!((Component)best).gameObject.activeSelf)
			{
				((Component)best).gameObject.SetActive(true);
			}
			HideLogoVfxChildren(((Component)best).transform);
			LogInfo($"Logo applied (score {hi}, name={((Object)((Component)best).gameObject).name}).");
			return true;
		}

		private static Transform? FindDeepNorthLogoRoot(Transform root)
		{
			string text = (((Object)root).name ?? string.Empty).ToLowerInvariant();
			if (text.Contains("logo") && text.Contains("deepnorth"))
			{
				return root;
			}
			for (int i = 0; i < root.childCount; i++)
			{
				Transform val = FindDeepNorthLogoRoot(root.GetChild(i));
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}

		private static void FindBestLogoImage(Transform root, ref Image? best, ref int hi)
		{
			Image component = ((Component)root).GetComponent<Image>();
			if ((Object)(object)component != (Object)null)
			{
				string text = (((Object)root).name ?? string.Empty).ToLowerInvariant();
				string text2 = (((Object)(object)component.sprite != (Object)null) ? ((Object)component.sprite).name.ToLowerInvariant() : string.Empty);
				if (text.Contains("logo") || text.Contains("valheim") || text.Contains("title") || text2.Contains("logo") || text2.Contains("valheim"))
				{
					int num = ScoreLogo(component);
					if (num > hi)
					{
						hi = num;
						best = component;
					}
				}
			}
			for (int i = 0; i < root.childCount; i++)
			{
				FindBestLogoImage(root.GetChild(i), ref best, ref hi);
			}
		}

		private static bool LogoLooksNamed(Image img)
		{
			string text = (((Object)((Component)img).gameObject).name ?? "").ToLowerInvariant();
			string text2 = (((Object)(object)img.sprite != (Object)null) ? ((Object)img.sprite).name.ToLowerInvariant() : "");
			if (!text.Contains("logo") && !text.Contains("valheim") && !text.Contains("title") && !text2.Contains("logo"))
			{
				return text2.Contains("valheim");
			}
			return true;
		}

		private static int ScoreLogo(Image img)
		{
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: 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_00ea: Unknown result type (might be due to invalid IL or missing references)
			string text = (((Object)((Component)img).gameObject).name ?? "").ToLowerInvariant();
			string text2 = (((Object)(object)img.sprite != (Object)null) ? ((Object)img.sprite).name.ToLowerInvariant() : "");
			int num = 0;
			if (text.Contains("logo"))
			{
				num += 100;
			}
			if (text.Contains("deepnorth"))
			{
				num += 40;
			}
			if (text.Contains("valheim") || text2.Contains("valheim"))
			{
				num += 80;
			}
			if (text.Contains("title"))
			{
				num += 40;
			}
			if (text2.Contains("logo"))
			{
				num += 50;
			}
			if (((Component)img).gameObject.activeInHierarchy)
			{
				num += 15;
			}
			if (((Behaviour)img).enabled)
			{
				num += 10;
			}
			RectTransform rectTransform = ((Graphic)img).rectTransform;
			if ((Object)(object)rectTransform != (Object)null)
			{
				Rect rect = rectTransform.rect;
				float width = ((Rect)(ref rect)).width;
				rect = rectTransform.rect;
				if (Mathf.Abs(width * ((Rect)(ref rect)).height) > 10000f)
				{
					num += 10;
				}
			}
			return num;
		}

		private static Sprite? LoadSpriteFromDisk(string path)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_0046: 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)
			try
			{
				byte[] data = File.ReadAllBytes(path);
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
				if (!TextureDecode.LoadImage(val, data, markNonReadable: false))
				{
					Object.Destroy((Object)(object)val);
					return null;
				}
				val.Apply(true, false);
				return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
			}
			catch (Exception ex)
			{
				LogWarn("logo load: " + ex.Message);
				return null;
			}
		}

		private static void HideLogoVfxChildren(Transform logoRoot)
		{
			for (int i = 0; i < logoRoot.childCount; i++)
			{
				HideLogoVfxWalk(logoRoot.GetChild(i));
			}
		}

		private static void HideLogoVfxWalk(Transform child)
		{
			string text = (((Object)child).name ?? string.Empty).ToLowerInvariant();
			if ((text.Contains("snow") || text.Contains("ember") || text.Contains("particle") || text.Contains("snowblow")) && ((Component)child).gameObject.activeSelf)
			{
				((Component)child).gameObject.SetActive(false);
				LogInfo("Deep North logo VFX hidden (" + ((Object)child).name + ").");
			}
			for (int i = 0; i < child.childCount; i++)
			{
				HideLogoVfxWalk(child.GetChild(i));
			}
		}

		private static void ApplyLogo(Image target, Sprite sp)
		{
			//IL_002b: 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_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: 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_0075: Unknown result type (might be due to invalid IL or missing references)
			target.sprite = sp;
			target.overrideSprite = sp;
			((Behaviour)target).enabled = true;
			target.preserveAspect = true;
			target.type = (Type)0;
			((Graphic)target).material = null;
			((Graphic)target).color = Color.white;
			if ((Object)(object)((Graphic)target).rectTransform != (Object)null)
			{
				RectTransform rectTransform = ((Graphic)target).rectTransform;
				Rect rect = sp.rect;
				float width = ((Rect)(ref rect)).width;
				rect = sp.rect;
				rectTransform.sizeDelta = new Vector2(width, ((Rect)(ref rect)).height);
				((Transform)((Graphic)target).rectTransform).localScale = Vector3.one;
			}
		}

		private static bool IsUsableTmpFont(TMP_FontAsset? font)
		{
			if ((Object)(object)font == (Object)null)
			{
				return false;
			}
			return (((Object)font).name ?? string.Empty).IndexOf("LiberationSans", StringComparison.OrdinalIgnoreCase) < 0;
		}

		private static void ApplyMenuFont(TextMeshProUGUI target, TextMeshProUGUI? template)
		{
			//IL_004e: 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)
			TMP_FontAsset val = null;
			if ((Object)(object)template != (Object)null && IsUsableTmpFont(((TMP_Text)template).font))
			{
				val = ((TMP_Text)template).font;
				((TMP_Text)target).fontSharedMaterial = ((TMP_Text)template).fontSharedMaterial;
				((TMP_Text)target).fontSize = Mathf.Clamp(((TMP_Text)template).fontSize - 1f, 16f, 28f);
				((Graphic)target).color = ((Graphic)template).color;
			}
			if ((Object)(object)val == (Object)null)
			{
				val = FindAnyUsableTmpFont();
				((TMP_Text)target).fontSize = 22f;
				if ((Object)(object)template == (Object)null || !IsUsableTmpFont(((TMP_Text)template).font))
				{
					((Graphic)target).color = new Color(0.93f, 0.79f, 0.42f);
				}
			}
			if ((Object)(object)val != (Object)null)
			{
				((TMP_Text)target).font = val;
				LogInfo("Discord title font: " + ((Object)val).name);
			}
			else
			{
				LogWarn("Discord title: no usable TMP font found yet.");
			}
		}

		private static TMP_FontAsset? FindAnyUsableTmpFont()
		{
			if (IsUsableTmpFont(_cachedDiscordFont))
			{
				return _cachedDiscordFont;
			}
			TMP_FontAsset val = null;
			FejdStartup instance = FejdStartup.instance;
			if ((Object)(object)instance != (Object)null)
			{
				TextMeshProUGUI[] componentsInChildren = ((Component)instance).GetComponentsInChildren<TextMeshProUGUI>(true);
				foreach (TextMeshProUGUI val2 in componentsInChildren)
				{
					if ((Object)(object)val2 != (Object)null && IsUsableTmpFont(((TMP_Text)val2).font))
					{
						val = ((TMP_Text)val2).font;
						break;
					}
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				TextMeshProUGUI[] componentsInChildren = Resources.FindObjectsOfTypeAll<TextMeshProUGUI>();
				foreach (TextMeshProUGUI val3 in componentsInChildren)
				{
					if ((Object)(object)val3 != (Object)null && IsUsableTmpFont(((TMP_Text)val3).font))
					{
						val = ((TMP_Text)val3).font;
						break;
					}
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				TMP_FontAsset[] array = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();
				foreach (TMP_FontAsset val4 in array)
				{
					if (IsUsableTmpFont(val4))
					{
						val = val4;
						break;
					}
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				TMP_FontAsset defaultFontAsset = TMP_Settings.defaultFontAsset;
				val = (IsUsableTmpFont(defaultFontAsset) ? defaultFontAsset : null);
			}
			_cachedDiscordFont = val;
			return val;
		}

		internal static void EnsureDiscordPanel(FejdStartup fejd, string reason)
		{
			if (!((Object)(object)fejd == (Object)null))
			{
				if ((Object)(object)_discordPanel == (Object)null)
				{
					CreateDiscordPanel(fejd);
				}
				else
				{
					DiscordPanelVisibility.Refresh(fejd, reason);
				}
			}
		}

		internal static void DestroyDiscordPanel()
		{
			if (Instance?._discordLogoCoroutine != null)
			{
				((MonoBehaviour)Instance).StopCoroutine(Instance._discordLogoCoroutine);
				Instance._discordLogoCoroutine = null;
			}
			if ((Object)(object)_discordPanel != (Object)null)
			{
				Object.Destroy((Object)(object)_discordPanel);
			}
			_discordPanel = null;
			_discordJoinButton = null;
			_discordLogoImage = null;
			DiscordPanelVisibility.ResetSessionState();
		}

		private static void EnsureParentedToStartMenuCanvas(FejdStartup fejd)
		{
			if (!((Object)(object)_discordPanel == (Object)null))
			{
				Canvas val = DiscordPanelVisibility.ResolveStartMenuCanvas(fejd);
				if (!((Object)(object)val == (Object)null) && !((Object)(object)_discordPanel.transform.parent == (Object)(object)((Component)val).transform))
				{
					_discordPanel.transform.SetParent(((Component)val).transform, false);
					ApplyDiscordPanelAnchors(_discordPanel.GetComponent<RectTransform>());
					LogInfo("Discord panel reparented to start-menu canvas (" + ((Object)val).name + ").");
				}
			}
		}

		private static void ApplyDiscordPanelAnchors(RectTransform? rootRt)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)rootRt == (Object)null))
			{
				rootRt.anchorMin = new Vector2(1f, 0f);
				rootRt.anchorMax = new Vector2(1f, 0f);
				rootRt.pivot = new Vector2(1f, 0f);
				rootRt.anchoredPosition = new Vector2(-36f, 105f);
				rootRt.sizeDelta = new Vector2(328f, 360f);
				((Transform)rootRt).localScale = Vector3.one;
			}
		}

		internal static TextMeshProUGUI? FindBestMenuTmpText(FejdStartup startup)
		{
			if ((Object)(object)startup == (Object)null)
			{
				return null;
			}
			TextMeshProUGUI result = null;
			int num = int.MinValue;
			TextMeshProUGUI[] componentsInChildren = ((Component)startup).GetComponentsInChildren<TextMeshProUGUI>(true);
			foreach (TextMeshProUGUI val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && IsUsableTmpFont(((TMP_Text)val).font))
				{
					string text = (((TMP_Text)val).text ?? "").ToLowerInvariant();
					string text2 = (((Object)((Component)val).gameObject).name ?? "").ToLowerInvariant();
					int num2 = 0;
					if (text.Contains("start game") || text.Contains("játék indítása"))
					{
						num2 += 300;
					}
					if (text.Contains("beállitások") || text.Contains("settings"))
					{
						num2 += 220;
					}
					if (text2.Contains("text"))
					{
						num2 += 20;
					}
					if (((TMP_Text)val).fontSize >= 20f)
					{
						num2 += 15;
					}
					if (num2 > num)
					{
						num = num2;
						result = val;
					}
				}
			}
			return result;
		}

		internal static Button? FindBestStartMenuButton(FejdStartup startup)
		{
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)startup == (Object)null)
			{
				return null;
			}
			GameObject val = (((Object)(object)startup.m_menuList != (Object)null) ? startup.m_menuList : startup.m_mainMenu);
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			Button result = null;
			int num = int.MinValue;
			Button[] componentsInChildren = val.GetComponentsInChildren<Button>(true);
			foreach (Button val2 in componentsInChildren)
			{
				if ((Object)(object)val2 == (Object)null || IsOurDiscordUi(((Component)val2).gameObject))
				{
					continue;
				}
				string text = GetButtonText(((Component)val2).gameObject).ToLowerInvariant();
				string text2 = (((Object)((Component)val2).gameObject).name ?? "").ToLowerInvariant();
				int num2 = 0;
				if (text.Contains("start game") || text.Contains("játék indítása"))
				{
					num2 += 300;
				}
				if (text.Contains("start") || text2.Contains("start"))
				{
					num2 += 150;
				}
				if (text.Contains("play"))
				{
					num2 += 120;
				}
				RectTransform component = ((Component)val2).GetComponent<RectTransform>();
				if ((Object)(object)component != (Object)null)
				{
					Rect rect = component.rect;
					float width = ((Rect)(ref rect)).width;
					rect = component.rect;
					if (Mathf.Abs(width * ((Rect)(ref rect)).height) > 5000f)
					{
						num2 += 10;
					}
				}
				if (num2 > num)
				{
					num = num2;
					result = val2;
				}
			}
			return result;
		}

		private static string GetButtonText(GameObject go)
		{
			TextMeshProUGUI[] componentsInChildren = go.GetComponentsInChildren<TextMeshProUGUI>(true);
			foreach (TextMeshProUGUI val in componentsInChildren)
			{
				if (!string.IsNullOrWhiteSpace(((TMP_Text)val).text))
				{
					return ((TMP_Text)val).text;
				}
			}
			Text[] componentsInChildren2 = go.GetComponentsInChildren<Text>(true);
			foreach (Text val2 in componentsInChildren2)
			{
				if (!string.IsNullOrWhiteSpace(val2.text))
				{
					return val2.text;
				}
			}
			return "";
		}

		internal static void SetButtonText(GameObject go, string txt)
		{
			TextMeshProUGUI[] componentsInChildren = go.GetComponentsInChildren<TextMeshProUGUI>(true);
			foreach (TextMeshProUGUI obj in componentsInChildren)
			{
				((TMP_Text)obj).richText = false;
				((TMP_Text)obj).text = txt;
			}
			Text[] componentsInChildren2 = go.GetComponentsInChildren<Text>(true);
			foreach (Text obj2 in componentsInChildren2)
			{
				obj2.supportRichText = false;
				obj2.text = txt;
			}
		}

		private static void NormalizeRectForLayoutGroup(RectTransform rt)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			((Transform)rt).localScale = Vector3.one;
			rt.anchorMin = new Vector2(0f, 0f);
			rt.anchorMax = new Vector2(1f, 1f);
			rt.pivot = new Vector2(0.5f, 0.5f);
			rt.anchoredPosition = Vector2.zero;
			rt.offsetMin = Vector2.zero;
			rt.offsetMax = Vector2.zero;
		}

		internal static void CreateDiscordPanel(FejdStartup? fejd = null)
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: 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_0130: 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_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Expected O, but got Unknown
			//IL_0215: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: 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)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0279: 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_027f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c1: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (fejd == null)
				{
					fejd = FejdStartup.instance;
				}
				if ((Object)(object)_discordPanel != (Object)null)
				{
					if ((Object)(object)fejd != (Object)null)
					{
						EnsureParentedToStartMenuCanvas(fejd);
						EnsureDiscordJoinButton(fejd);
						DiscordPanelVisibility.Refresh(fejd, "Discord panel reuse");
					}
				}
				else
				{
					if ((Object)(object)fejd == (Object)null || (Object)(object)Instance == (Object)null)
					{
						return;
					}
					Canvas val = DiscordPanelVisibility.ResolveStartMenuCanvas(fejd);
					if ((Object)(object)val == (Object)null)
					{
						LogInfo("Discord panel deferred: start-menu canvas not ready.");
						return;
					}
					_discordPanel = new GameObject("CustomMainMenuDiscordPanel");
					_discordPanel.transform.SetParent(((Component)val).transform, false);
					ApplyDiscordPanelAnchors(_discordPanel.AddComponent<RectTransform>());
					VerticalLayoutGroup obj = _discordPanel.AddComponent<VerticalLayoutGroup>();
					((LayoutGroup)obj).childAlignment = (TextAnchor)4;
					((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true;
					((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = false;
					((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = true;
					((HorizontalOrVerticalLayoutGroup)obj).spacing = 16f;
					_discordPanel.AddComponent<ContentSizeFitter>().verticalFit = (FitMode)2;
					TextMeshProUGUI template = FindBestMenuTmpText(fejd);
					GameObject val2 = new GameObject("DiscordTitle", new Type[1] { typeof(RectTransform) });
					val2.SetActive(false);
					val2.transform.SetParent(_discordPanel.transform, false);
					NormalizeRectForLayoutGroup(val2.GetComponent<RectTransform>());
					LayoutElement obj2 = val2.AddComponent<LayoutElement>();
					obj2.flexibleWidth = 1f;
					obj2.preferredWidth = 300f;
					obj2.preferredHeight = 90f;
					TextMeshProUGUI obj3 = val2.AddComponent<TextMeshProUGUI>();
					((TMP_Text)obj3).richText = false;
					((TMP_Text)obj3).text = "Need help? Join Discord!";
					((TMP_Text)obj3).horizontalAlignment = (HorizontalAlignmentOptions)2;
					((TMP_Text)obj3).verticalAlignment = (VerticalAlignmentOptions)512;
					((TMP_Text)obj3).textWrappingMode = (TextWrappingModes)1;
					((TMP_Text)obj3).overflowMode = (TextOverflowModes)0;
					((TMP_Text)obj3).margin = Vector4.zero;
					((TMP_Text)obj3).enableAutoSizing = false;
					((Graphic)obj3).raycastTarget = false;
					ApplyMenuFont(obj3, template);
					val2.SetActive(true);
					GameObject val3 = new GameObject("DiscordLogo");
					val3.transform.SetParent(_discordPanel.transform, false);
					LayoutElement obj4 = val3.AddComponent<LayoutElement>();
					obj4.preferredHeight = 150f;
					obj4.preferredWidth = 300f;
					_discordLogoImage = val3.AddComponent<Image>();
					_discordLogoImage.type = (Type)0;
					((Graphic)_discordLogoImage).color = Color.white;
					((Graphic)_discordLogoImage).material = null;
					_discordLogoImage.preserveAspect = true;
					((Graphic)_discordLogoImage).raycastTarget = false;
					GameObject val4 = new GameObject("DiscordGlyph");
					val4.transform.SetParent(val3.transform, false);
					RectTransform obj5 = val4.AddComponent<RectTransform>();
					obj5.anchorMin = Vector2.zero;
					obj5.anchorMax = Vector2.one;
					Vector2 offsetMin = (obj5.offsetMax = Vector2.zero);
					obj5.offsetMin = offsetMin;
					Text obj6 = val4.AddComponent<Text>();
					obj6.text = "DIS";
					obj6.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
					obj6.fontSize = 24;
					obj6.fontStyle = (FontStyle)1;
					obj6.alignment = (TextAnchor)4;
					((Graphic)obj6).color = Color.white;
					EnsureDiscordJoinButton(fejd);
					Instance._discordLogoCoroutine = ((MonoBehaviour)Instance).StartCoroutine(Instance.LoadDiscordLogoDelayed());
					HideVanillaDiscordButton(fejd);
					DiscordPanelVisibility.RegisterPanel(_discordPanel);
					DiscordPanelVisibility.Refresh(fejd, "Discord panel created");
					ManualLogSource? modLog = ModLog;
					if (modLog != null)
					{
						modLog.LogInfo((object)("Discord panel ready (canvas=" + ((Object)val).name + ")."));
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource? modLog2 = ModLog;
				if (modLog2 != null)
				{
					modLog2.LogError((object)("Discord panel failed: " + ex));
				}
			}
		}

		private static void EnsureDiscordJoinButton(FejdStartup fejd, float discordContentWidth = 300f)
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Expected O, but got Unknown
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Expected O, but got Unknown
			if ((Object)(object)_discordPanel == (Object)null)
			{
				return;
			}
			if ((Object)(object)_discordJoinButton != (Object)null)
			{
				_discordJoinButton.SetActive(true);
				return;
			}
			Button val = FindBestStartMenuButton(fejd);
			if ((Object)(object)val != (Object)null)
			{
				GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, _discordPanel.transform, false);
				val2.SetActive(true);
				LayoutElement obj = val2.GetComponent<LayoutElement>() ?? val2.AddComponent<LayoutElement>();
				obj.preferredWidth = discordContentWidth;
				obj.preferredHeight = 46f;
				Button component = val2.GetComponent<Button>();
				if ((Object)(object)component != (Object)null)
				{
					component.onClick = new ButtonClickedEvent();
					ButtonClickedEvent onClick = component.onClick;
					object obj2 = <>O.<0>__OnDiscordJoinClicked;
					if (obj2 == null)
					{
						UnityAction val3 = OnDiscordJoinClicked;
						<>O.<0>__OnDiscordJoinClicked = val3;
						obj2 = (object)val3;
					}
					((UnityEvent)onClick).AddListener((UnityAction)obj2);
					SetButtonText(val2, "Click here to join Discord!");
				}
				_discordJoinButton = val2;
			}
			else
			{
				_discordJoinButton = CreateFallbackDiscordButton(_discordPanel.transform, discordContentWidth, fejd);
			}
		}

		private static GameObject CreateFallbackDiscordButton(Transform parent, float width, FejdStartup fejd)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: 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_00c0: Expected O, but got Unknown
			GameObject val = new GameObject("DiscordJoinButton", new Type[5]
			{
				typeof(RectTransform),
				typeof(CanvasRenderer),
				typeof(Image),
				typeof(Button),
				typeof(LayoutElement)
			});
			val.transform.SetParent(parent, false);
			LayoutElement component = val.GetComponent<LayoutElement>();
			component.preferredWidth = width;
			component.preferredHeight = 46f;
			((Graphic)val.GetComponent<Image>()).color = new Color(0.18f, 0.14f, 0.08f, 0.92f);
			ButtonClickedEvent onClick = val.GetComponent<Button>().onClick;
			object obj = <>O.<0>__OnDiscordJoinClicked;
			if (obj == null)
			{
				UnityAction val2 = OnDiscordJoinClicked;
				<>O.<0>__OnDiscordJoinClicked = val2;
				obj = (object)val2;
			}
			((UnityEvent)onClick).AddListener((UnityAction)obj);
			GameObject val3 = new GameObject("Text", new Type[1] { typeof(RectTransform) });
			val3.transform.SetParent(val.transform, false);
			NormalizeRectForLayoutGroup(val3.GetComponent<RectTransform>());
			TextMeshProUGUI obj2 = val3.AddComponent<TextMeshProUGUI>();
			((TMP_Text)obj2).richText = false;
			((TMP_Text)obj2).text = "Click here to join Discord!";
			((TMP_Text)obj2).horizontalAlignment = (HorizontalAlignmentOptions)2;
			((TMP_Text)obj2).verticalAlignment = (VerticalAlignmentOptions)512;
			((TMP_Text)obj2).enableAutoSizing = false;
			((Graphic)obj2).raycastTarget = false;
			ApplyMenuFont(obj2, FindBestMenuTmpText(fejd));
			return val;
		}

		private static void OnDiscordJoinClicked()
		{
			if (!DiscordPanelVisibility.TryOpenInviteUrl())
			{
				LogWarn("Discord invite URL is missing or invalid in config.");
			}
		}

		private IEnumerator LoadDiscordLogoDelayed()
		{
			yield return null;
			if ((Object)(object)_discordLogoImage == (Object)null)
			{
				yield break;
			}
			string discordLogoPath = GetDiscordLogoPath();
			if (!File.Exists(discordLogoPath))
			{
				yield break;
			}
			Sprite val = LoadSpriteFromDisk(discordLogoPath);
			if ((Object)(object)val != (Object)null && (Object)(object)_discordLogoImage != (Object)null)
			{
				_discordLogoImage.sprite = val;
				_discordLogoImage.overrideSprite = val;
				_discordLogoImage.type = (Type)0;
				((Graphic)_discordLogoImage).color = Color.white;
				((Graphic)_discordLogoImage).material = null;
				foreach (Transform item in ((Component)_discordLogoImage).transform)
				{
					Transform val2 = item;
					if (((Object)val2).name == "DiscordGlyph")
					{
						((Component)val2).gameObject.SetActive(false);
					}
				}
			}
			_discordLogoCoroutine = null;
		}

		internal static void PauseMenuMusicForCinematic()
		{
			AudioSource val = Instance?._menuMusicSource;
			if (!((Object)(object)val == (Object)null) && val.isPlaying)
			{
				val.Pause();
				Instance._menuMusicPausedForCinematic = true;
				LogInfo("Menu music paused for cinematic.");
			}
		}

		internal static float GetVanillaMusicGain()
		{
			try
			{
				if ((Object)(object)MusicMan.instance != (Object)null)
				{
					return Mathf.Clamp01(MusicMan.m_masterMusicVolume);
				}
				float num = PlatformPrefs.GetFloat("MusicVolume", 1f);
				float num2 = PlatformPrefs.GetFloat("MasterVolume", 1f);
				return Mathf.Clamp01(num * num2);
			}
			catch
			{
				return 1f;
			}
		}

		internal static void ApplyMenuMusicVolume()
		{
			CustomMainMenuPlugin instance = Instance;
			AudioSource val = instance?._menuMusicSource;
			if (!((Object)(object)val == (Object)null))
			{
				val.volume = 0.72f * GetVanillaMusicGain() * instance._menuMusicFadeFactor;
			}
		}

		internal static void ResumeMenuMusicAfterCinematic()
		{
			if (MainMenuActive && !MenuMusicFadeCommittedForSession)
			{
				CustomMainMenuPlugin instance = Instance;
				if ((Object)(object)instance?._menuMusicSource != (Object)null && instance._menuMusicPausedForCinematic)
				{
					instance._menuMusicSource.UnPause();
					instance._menuMusicPausedForCinematic = false;
					ApplyMenuMusicVolume();
					LogInfo("Menu music resumed after cinematic.");
				}
				else if (HasCustomMenuMusic())
				{
					StartMenuMusic();
				}
			}
		}

		internal static void OnVanillaStartupMusicReset()
		{
			if (!MainMenuActive || MenuMusicFadeCommittedForSession || CinematicsManager.IsStartedPlaying())
			{
				return;
			}
			SilenceMusicManForMainMenu();
			if (!HasCustomMenuMusic())
			{
				return;
			}
			AudioSource val = Instance?._menuMusicSource;
			if ((Object)(object)val != (Object)null && (Object)(object)val.clip != (Object)null)
			{
				ApplyMenuMusicVolume();
				if (!val.isPlaying)
				{
					val.Play();
				}
			}
			else
			{
				StartMenuMusic();
			}
		}

		internal static void StartMenuMusic()
		{
			if (!((Object)(object)Instance == (Object)null) && !CinematicsManager.IsStartedPlaying())
			{
				if (Instance._menuMusicStartCoroutine != null)
				{
					((MonoBehaviour)Instance).StopCoroutine(Instance._menuMusicStartCoroutine);
					Instance._menuMusicStartCoroutine = null;
				}
				Instance._menuMusicStartCoroutine = ((MonoBehaviour)Instance).StartCoroutine(LoadAndPlayMusic());
			}
		}

		private static IEnumerator LoadAndPlayMusic()
		{
			yield return (object)new WaitForSecondsRealtime(0.1f);
			string musicPath = GetMusicPath();
			if (!File.Exists(musicPath))
			{
				LogWarn("mainmenu.ogg missing: " + musicPath);
				yield break;
			}
			string absoluteUri = new Uri(Path.GetFullPath(musicPath)).AbsoluteUri;
			UnityWebRequest req = UnityWebRequestMultimedia.GetAudioClip(absoluteUri, (AudioType)14);
			try
			{
				yield return req.SendWebRequest();
				AudioClip content = DownloadHandlerAudioClip.GetContent(req);
				if ((Object)(object)content == (Object)null || (Object)(object)Instance == (Object)null)
				{
					LogWarn("Music failed: " + req.error);
					yield break;
				}
				EnsureMenuMusicAudio(Instance);
				AudioSource menuMusicSource = Instance._menuMusicSource;
				menuMusicSource.clip = content;
				menuMusicSource.loop = true;
				AttachMenuMusicMixer(menuMusicSource);
				Instance._menuMusicFadeFactor = 1f;
				ApplyMenuMusicVolume();
				if (!menuMusicSource.isPlaying)
				{
					menuMusicSource.Play();
				}
				LogInfo("Menu music playing.");
				if ((Object)(object)Instance != (Object)null)
				{
					Instance._menuMusicStartCoroutine = null;
				}
			}
			finally
			{
				((IDisposable)req)?.Dispose();
			}
		}

		private static void EnsureMenuMusicAudio(CustomMainMenuPlugin plug)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			if (!((Object)(object)plug._menuMusicSource != (Object)null) || !((Object)(object)plug._menuMusicGo != (Object)null))
			{
				plug._menuMusicGo = new GameObject("CustomMainMenuMusicAudio");
				Object.DontDestroyOnLoad((Object)(object)plug._menuMusicGo);
				plug._menuMusicSource = plug._menuMusicGo.AddComponent<AudioSource>();
				plug._menuMusicSource.playOnAwake = false;
				plug._menuMusicSource.loop = true;
				plug._menuMusicSource.spatialBlend = 0f;
				AttachMenuMusicMixer(plug._menuMusicSource);
			}
		}

		private static void AttachMenuMusicMixer(AudioSource src)
		{
			try
			{
				MusicMan instance = MusicMan.instance;
				if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.m_musicMixer == (Object)null))
				{
					src.outputAudioMixerGroup = instance.m_musicMixer;
				}
			}
			catch
			{
			}
		}

		internal static void StopMenuMusic()
		{
			CustomMainMenuPlugin instance = Instance;
			if ((Object)(object)instance?._menuMusicSource != (Object)null)
			{
				instance._menuMusicSource.Stop();
				instance._menuMusicSource.clip = null;
			}
			if ((Object)(object)instance?._menuMusicGo != (Object)null)
			{
				Object.Destroy((Object)(object)instance._menuMusicGo);
				instance._menuMusicGo = null;
				instance._menuMusicSource = null;
			}
			if ((Object)(object)instance != (Object)null)
			{
				instance._menuMusicFadeFactor = 1f;
			}
		}

		internal static void FadeOutAndStopMenuMusic()
		{
			if ((Object)(object)Instance == (Object)null)
			{
				StopMenuMusic();
				return;
			}
			if ((Object)(object)Instance._menuMusicSource == (Object)null || (Object)(object)Instance._menuMusicGo == (Object)null)
			{
				StopMenuMusic();
				return;
			}
			if (Instance._menuMusicFadeCoroutine != null)
			{
				((MonoBehaviour)Instance).StopCoroutine(Instance._menuMusicFadeCoroutine);
				Instance._menuMusicFadeCoroutine = null;
			}
			Instance._menuMusicPausedForCinematic = false;
			Instance._menuMusicFadeCoroutine = ((MonoBehaviour)Instance).StartCoroutine(FadeMusic(2.25f));
		}

		private static IEnumerator FadeMusic(float seconds)
		{
			CustomMainMenuPlugin plug = Instance;
			if ((Object)(object)plug?._menuMusicSource == (Object)null)
			{
				StopMenuMusic();
				yield break;
			}
			float start = plug._menuMusicFadeFactor;
			float t = 0f;
			while (t < seconds && (Object)(object)plug._menuMusicSource != (Object)null)
			{
				t += Time.unscaledDeltaTime;
				plug._menuMusicFadeFactor = Mathf.Lerp(start, 0f, Mathf.Clamp01(t / seconds));
				ApplyMenuMusicVolume();
				yield return null;
			}
			if ((Object)(object)plug != (Object)null)
			{
				plug._menuMusicFadeCoroutine = null;
			}
			StopMenuMusic();
			LogInfo("Menu music stopped after fade.");
		}
	}
	internal static class DiscordPanelVisibility
	{
		private static ConfigEntry<bool>? _visibleOnlyOnStartMenu;

		private static ConfigEntry<string>? _discordInviteUrl;

		private static bool? _lastAppliedVisible;

		internal static void BindConfig(ConfigFile config)
		{
			_visibleOnlyOnStartMenu = config.Bind<bool>("Discord Panel", "VisibleOnlyOnStartMenu", true, "When true, the Discord panel is visible only on the main Start Game screen. Hidden on character/world select and during load.");
			_discordInviteUrl = config.Bind<string>("Discord Panel", "DiscordInviteUrl", "https://discord.gg/yX9tv3FXY6", "Discord invite opened by the panel button (http or https). Leave empty to disable the link.");
		}

		internal static bool TryOpenInviteUrl()
		{
			string text = (_discordInviteUrl?.Value ?? string.Empty).Trim();
			if (!IsValidInviteUrl(text))
			{
				return false;
			}
			Application.OpenURL(text);
			CustomMainMenuPlugin.LogInfo("Discord opened.");
			return true;
		}

		private static bool IsValidInviteUrl(string url)
		{
			if (string.IsNullOrWhiteSpace(url))
			{
				return false;
			}
			if (!Uri.TryCreate(url, UriKind.Absolute, out Uri result))
			{
				return false;
			}
			if (!(result.Scheme == Uri.UriSchemeHttp))
			{
				return result.Scheme == Uri.UriSchemeHttps;
			}
			return true;
		}

		internal static bool IsGatingEnabled()
		{
			if (_visibleOnlyOnStartMenu != null)
			{
				return _visibleOnlyOnStartMenu.Value;
			}
			return true;
		}

		internal static void RegisterPanel(GameObject? panelRoot)
		{
			CustomMainMenuPlugin.SetDiscordPanelRoot(panelRoot);
		}

		internal static void EnsureReady(FejdStartup? fejd, string reason)
		{
			if (CustomMainMenuPlugin.MainMenuActive && !((Object)(object)fejd == (Object)null))
			{
				CustomMainMenuPlugin.EnsureDiscordPanel(fejd, reason);
			}
		}

		internal static void Refresh(FejdStartup? fejd, string reason)
		{
			GameObject discordPanelRoot = CustomMainMenuPlugin.DiscordPanelRoot;
			if (!((Object)(object)discordPanelRoot == (Object)null))
			{
				bool visible = ComputeShouldBeVisible(fejd);
				ApplyVisible(discordPanelRoot, visible, reason);
			}
		}

		internal static void Hide(string reason)
		{
			GameObject discordPanelRoot = CustomMainMenuPlugin.DiscordPanelRoot;
			if (!((Object)(object)discordPanelRoot == (Object)null))
			{
				ApplyVisible(discordPanelRoot, visible: false, reason);
			}
		}

		internal static bool ComputeShouldBeVisible(FejdStartup? fejd)
		{
			if (!CustomMainMenuPlugin.MainMenuActive)
			{
				return false;
			}
			if (!IsGatingEnabled())
			{
				return !IsOverlayBlockingStartMenu(fejd);
			}
			if ((Object)(object)fejd == (Object)null || (Object)(object)fejd.m_mainMenu == (Object)null)
			{
				return false;
			}
			if (IsOverlayBlockingStartMenu(fejd))
			{
				return false;
			}
			return fejd.m_mainMenu.activeInHierarchy;
		}

		internal static bool IsOverlayBlockingStartMenu(FejdStartup? fejd)
		{
			if (IsIntroOrCinematicPlaying())
			{
				return true;
			}
			if ((Object)(object)fejd == (Object)null)
			{
				return false;
			}
			if ((Object)(object)fejd.m_cinematicsMenuList != (Object)null && fejd.m_cinematicsMenuList.activeInHierarchy)
			{
				return true;
			}
			EulaWindow eulaWindow = fejd.m_eulaWindow;
			if ((Object)(object)eulaWindow != (Object)null && eulaWindow.IsWindowActive())
			{
				return true;
			}
			return false;
		}

		internal static bool IsIntroOrCinematicPlaying()
		{
			return CinematicsManager.IsStartedPlaying();
		}

		internal static Canvas? ResolveStartMenuCanvas(FejdStartup fejd)
		{
			if ((Object)(object)fejd == (Object)null)
			{
				return null;
			}
			if ((Object)(object)fejd.m_mainMenu != (Object)null)
			{
				Canvas componentInParent = fejd.m_mainMenu.GetComponentInParent<Canvas>(true);
				if ((Object)(object)componentInParent != (Object)null)
				{
					return componentInParent;
				}
			}
			Canvas componentInParent2 = ((Component)fejd).GetComponentInParent<Canvas>(true);
			if ((Object)(object)componentInParent2 != (Object)null)
			{
				return componentInParent2;
			}
			return ((Component)fejd).GetComponentInChildren<Canvas>(true);
		}

		private static void ApplyVisible(GameObject panel, bool visible, string reason)
		{
			if (_lastAppliedVisible != visible || panel.activeSelf != visible)
			{
				panel.SetActive(visible);
				_lastAppliedVisible = visible;
				CustomMainMenuPlugin.LogInfo(string.Format("Discord panel {0} ({1}); gating={2}, mainMenuActive={3}.", visible ? "shown" : "hidden", reason, IsGatingEnabled(), IsMainMenuRootActive(FejdStartup.instance)));
			}
		}

		private static bool IsMainMenuRootActive(FejdStartup? fejd)
		{
			if ((Object)(object)fejd?.m_mainMenu != (Object)null)
			{
				return fejd.m_mainMenu.activeInHierarchy;
			}
			return false;
		}

		internal static void ResetSessionState()
		{
			_lastAppliedVisible = null;
		}
	}
	internal static class LoadingScreens
	{
		internal struct LoadingTargetResult
		{
			internal bool IsValid;

			internal bool IsRaw;

			internal bool RestoreOnClear;

			internal Image? Image;

			internal RawImage? RawImage;

			internal Sprite? OriginalSprite;

			internal Color OriginalColor;

			internal int Score;

			internal string Path;

			internal string ObjectName;
		}

		private const float MaxLoadWaitSeconds = 2400f;

		private const int MinimumValidScore = 300;

		private const float LoadingFadeOutSeconds = 0.6f;

		private static Coroutine? _fadeCoroutine;

		private static Coroutine? _timeoutCoroutine;

		private static bool _sessionArmed;

		private static bool _spawnHookAttached;

		private static bool _fallbackScanDone;

		private static string? _artPath;

		private static LoadingTargetResult _applied;

		private static Sprite? _appliedSprite;

		internal static bool LoadingArtSessionActive => _applied.IsValid;

		internal static void ResetForMainMenu()
		{
			StopAllWatchers("main menu reset");
		}

		internal static void StopAllWatchers(string reason)
		{
			if (_sessionArmed || _applied.IsValid)
			{
				LogLoading("Loading art session ended (" + reason + ").");
			}
			StopCoroutineRef(ref _fadeCoroutine);
			StopCoroutineRef(ref _timeoutCoroutine);
			DetachSpawnHook();
			ClearLoadingTarget(_applied);
			DestroyAppliedSprite();
			_applied = default(LoadingTargetResult);
			_sessionArmed = false;
			_fallbackScanDone = false;
			_artPath = null;
		}

		internal static void TryStartLoadingScreenWatcher(string trigger)
		{
			if (!CustomMainMenuPlugin.EnableCustomLoadingScreens || (Object)(object)CustomMainMenuPlugin.Instance == (Object)null)
			{
				LogLoading("Loading art skipped (" + trigger + "): custom loading screens disabled or plugin missing.");
			}
			else if (CustomMainMenuPlugin.MainMenuActive)
			{
				LogLoading("Loading art deferred (" + trigger + "): still on Fejd main menu (world select / UI).");
			}
			else if (!_sessionArmed && !_applied.IsValid)
			{
				_artPath = CustomMainMenuPlugin.GetRandomLoadingArtPath();
				if (string.IsNullOrEmpty(_artPath) || !File.Exists(_artPath))
				{
					LogLoading("Loading art skipped (" + trigger + "): no art files in the LoadingArt folder.");
					return;
				}
				_sessionArmed = true;
				_fallbackScanDone = false;
				AttachSpawnHook();
				_timeoutCoroutine = ((MonoBehaviour)CustomMainMenuPlugin.Instance).StartCoroutine(TimeoutGuardCoroutine());
				LogLoading("Loading art armed (" + trigger + "): " + _artPath);
				TryApplyToHud(Hud.instance, trigger);
			}
		}

		internal static void OnHudAwake(Hud hud)
		{
			if (_sessionArmed && !_applied.IsValid)
			{
				TryApplyToHud(hud, "Hud.Awake");
			}
		}

		private static void TryApplyToHud(Hud? hud, string trigger)
		{
			if ((Object)(object)hud == (Object)null || _applied.IsValid || string.IsNullOrEmpty(_artPath))
			{
				return;
			}
			if ((Object)(object)hud.m_loadingImage != (Object)null)
			{
				if (TryApplyHudLoadingArt(_artPath, hud.m_loadingImage, out LoadingTargetResult result, out Sprite sprite))
				{
					_applied = result;
					_appliedSprite = sprite;
					LogLoading("Loading art applied via Hud.m_loadingImage (" + trigger + ").");
				}
			}
			else
			{
				if (_fallbackScanDone)
				{
					return;
				}
				_fallbackScanDone = true;
				Sprite val = SpriteFromFile(_artPath);
				if (!((Object)(object)val == (Object)null))
				{
					Stopwatch stopwatch = Stopwatch.StartNew();
					LoadingTargetResult loadingTargetResult = FindBestConnectedWorldLoadingTarget();
					stopwatch.Stop();
					LogLoading($"Loading UI fallback scan ({trigger}): {stopwatch.ElapsedMilliseconds} ms, valid={loadingTargetResult.IsValid}, score={loadingTargetResult.Score}.");
					if (loadingTargetResult.IsValid && ApplyLoadingTargetResult(loadingTargetResult, val))
					{
						_applied = loadingTargetResult;
						_appliedSprite = val;
						LogLoading("Loading art applied (" + trigger + "): " + loadingTargetResult.ObjectName + " @ " + loadingTargetResult.Path + ".");
					}
					else
					{
						DestroySprite(val);
					}
				}
			}
		}

		private static void AttachSpawnHook()
		{
			if (_spawnHookAttached)
			{
				return;
			}
			try
			{
				Game.m_playerInitialSpawn += OnPlayerInitialSpawn;
				_spawnHookAttached = true;
			}
			catch (Exception ex)
			{
				CustomMainMenuPlugin.LogWarn("Could not subscribe to Game.m_playerInitialSpawn: " + ex.Message);
			}
		}

		private static void DetachSpawnHook()
		{
			if (_spawnHookAttached)
			{
				try
				{
					Game.m_playerInitialSpawn -= OnPlayerInitialSpawn;
				}
				catch (Exception ex)
				{
					CustomMainMenuPlugin.LogWarn("Could not unsubscribe from Game.m_playerInitialSpawn: " + ex.Message);
				}
				_spawnHookAttached = false;
			}
		}

		private static void OnPlayerInitialSpawn()
		{
			DetachSpawnHook();
			StopCoroutineRef(ref _timeoutCoroutine);
			CustomMainMenuPlugin.IsWorldFullyLoaded();
			_sessionArmed = false;
			FadeOutAndClearLoadingTarget(_applied);
		}

		private static IEnumerator TimeoutGuardCoroutine()
		{
			yield return (object)new WaitForSecondsRealtime(2400f);
			_timeoutCoroutine = null;
			LogLoading("Loading art timeout reached; restoring vanilla loading screen.");
			StopAllWatchers("timeout");
		}

		private static void StopCoroutineRef(ref Coroutine? coroutine)
		{
			if (coroutine != null)
			{
				if ((Object)(object)CustomMainMenuPlugin.Instance != (Object)null)
				{
					((MonoBehaviour)CustomMainMenuPlugin.Instance).StopCoroutine(coroutine);
				}
				coroutine = null;
			}
		}

		private static void DestroyAppliedSprite()
		{
			DestroySprite(_appliedSprite);
			_appliedSprite = null;
		}

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

		private static void LogLoading(string message)
		{
			CustomMainMenuPlugin.LogInfo(message);
		}

		private static bool TryApplyHudLoadingArt(string path, Image image, out LoadingTargetResult result, out Sprite? sprite)
		{
			//IL_0064: 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)
			result = default(LoadingTargetResult);
			sprite = null;
			try
			{
				sprite = SpriteFromFile(path);
				if ((Object)(object)sprite == (Object)null)
				{
					return false;
				}
				result = new LoadingTargetResult
				{
					IsValid = true,
					IsRaw = false,
					RestoreOnClear = true,
					Image = image,
					RawImage = null,
					OriginalSprite = image.sprite,
					OriginalColor = ((Graphic)image).color,
					Score = 10000,
					Path = GetHierarchyPath(((Component)image).transform),
					ObjectName = ((Object)((Component)image).gameObject).name
				};
				if (!ApplyLoadingTargetResult(result, sprite))
				{
					DestroySprite(sprite);
					sprite = null;
					result = default(LoadingTargetResult);
					return false;
				}
				return true;
			}
			catch (Exception ex)
			{
				CustomMainMenuPlugin.LogWarn("Hud loading art failed: " + ex.Message);
				DestroySprite(sprite);
				sprite = null;
				result = default(LoadingTargetResult);
				return false;
			}
		}

		private static Sprite? SpriteFromFile(string absolutePath)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				byte[] data = File.ReadAllBytes(absolutePath);
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
				if (!TextureDecode.LoadImage(val, data, markNonReadable: true))
				{
					Object.Destroy((Object)(object)val);
					return null;
				}
				return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f));
			}
			catch
			{
				return null;
			}
		}

		private static void FadeOutAndClearLoadingTarget(LoadingTargetResult result)
		{
			if (!result.IsValid || (Object)(object)CustomMainMenuPlugin.Instance == (Object)null)
			{
				ClearLoadingTarget(result);
				DestroyAppliedSprite();
				_applied = default(LoadingTargetResult);
			}
			else
			{
				StopCoroutineRef(ref _fadeCoroutine);
				_fadeCoroutine = ((MonoBehaviour)CustomMainMenuPlugin.Instance).StartCoroutine(LoadingFadeCoroutine(result));
			}
		}

		private static IEnumerator LoadingFadeCoroutine(LoadingTargetResult result)
		{
			float elapsed = 0f;
			float startAlpha = 1f;
			if (result.IsRaw && (Object)(object)result.RawImage != (Object)null)
			{
				startAlpha = ((Graphic)result.RawImage).canvasRenderer.GetAlpha();
			}
			else if ((Object)(object)result.Image != (Object)null)
			{
				startAlpha = ((Graphic)result.Image).canvasRenderer.GetAlpha();
			}
			while (elapsed < 0.6f)
			{
				elapsed += Time.unscaledDeltaTime;
				float num = Mathf.Clamp01(elapsed / 0.6f);
				float a = Mathf.Lerp(startAlpha, 0f, num);
				TryApplyAlpha(result, a);
				yield return null;
			}
			ClearLoadingTarget(result);
			DestroyAppliedSprite();
			_applied = default(LoadingTargetResult);
			_fadeCoroutine = null;
		}

		private static void TryApplyAlpha(LoadingTargetResult result, float a)
		{
			//IL_0041: 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)
			if (result.IsValid)
			{
				Color color = default(Color);
				((Color)(ref color))..ctor(1f, 1f, 1f, Mathf.Clamp01(a));
				if (result.IsRaw && (Object)(object)result.RawImage != (Object)null)
				{
					((Graphic)result.RawImage).color = color;
					((Graphic)result.RawImage).SetAllDirty();
				}
				else if (!result.IsRaw && (Object)(object)result.Image != (Object)null)
				{
					((Graphic)result.Image).color = color;
					((Graphic)result.Image).SetAllDirty();
				}
			}
		}

		internal static LoadingTargetResult FindBestConnectedWorldLoadingTarget()
		{
			LoadingTargetResult result = new LoadingTargetResult
			{
				IsValid = false,
				IsRaw = false,
				Image = null,
				RawImage = null,
				Score = int.MinValue,
				Path = string.Empty,
				ObjectName = string.Empty
			};
			Image[] array = Resources.FindObjectsOfTypeAll<Image>();
			foreach (Image val in array)
			{
				if ((Object)(object)val != (Object)null && (Object)(object)((Component)val).gameObject != (Object)null)
				{
					int num = CalculateConnectedWorldLoadingImageScore(val);
					if (num > result.Score)
					{
						result.IsValid = num >= 300;
						result.IsRaw = false;
						result.Image = val;
						result.RawImage = null;
						result.Score = num;
						result.Path = GetHierarchyPath(((Component)val).transform);
						result.ObjectName = ((Object)((Component)val).gameObject).name;
					}
				}
			}
			RawImage[] array2 = Resources.FindObjectsOfTypeAll<RawImage>();
			foreach (RawImage val2 in array2)
			{
				if ((Object)(object)val2 != (Object)null && (Object)(object)((Component)val2).gameObject != (Object)null)
				{
					int num2 = CalculateConnectedWorldLoadingRawImageScore(val2);
					if (num2 > result.Score)
					{
						result.IsValid = num2 >= 300;
						result.IsRaw = true;
						result.Image = null;
						result.RawImage = val2;
						result.Score = num2;
						result.Path = GetHierarchyPath(((Component)val2).transform);
						result.ObjectName = ((Object)((Component)val2).gameObject).name;
					}
				}
			}
			return result;
		}

		private static bool ApplyLoadingTargetResult(LoadingTargetResult result, Sprite customSprite)
		{
			if (!result.IsValid || (Object)(object)customSprite == (Object)null)
			{
				return false;
			}
			if (result.IsRaw)
			{
				if ((Object)(object)result.RawImage == (Object)null)
				{
					return false;
				}
				ApplyLoadingRawImage(result.RawImage, customSprite);
			}
			else
			{
				if ((Object)(object)result.Image == (Object)null)
				{
					return false;
				}
				ApplyLoadingImage(result.Image, customSprite);
			}
			return true;
		}

		private static void ApplyLoadingImage(Image target, Sprite customSprite)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			target.sprite = customSprite;
			target.overrideSprite = customSprite;
			((Behaviour)target).enabled = true;
			target.preserveAspect = false;
			target.type = (Type)0;
			((Graphic)target).material = null;
			((Graphic)target).color = Color.white;
			StretchToFullscreen(((Graphic)target).rectTransform);
			((Graphic)target).SetAllDirty();
		}

		private static void ApplyLoadingRawImage(RawImage target, Sprite customSprite)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			target.texture = (Texture)(object)customSprite.texture;
			((Behaviour)target).enabled = true;
			((Graphic)target).material = null;
			((Graphic)target).color = Color.white;
			StretchToFullscreen(((Graphic)target).rectTransform);
			((Graphic)target).SetAllDirty();
		}

		private static void ClearLoadingTarget(LoadingTargetResult result)
		{
			//IL_00c8: 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_0145: Unknown result type (might be due to invalid IL or missing references)
			if (result.IsValid)
			{
				if (result.RestoreOnClear && !result.IsRaw && (Object)(object)result.Image != (Object)null && (Object)(object)((Component)result.Image).gameObject != (Object)null)
				{
					result.Image.sprite = result.OriginalSprite;
					result.Image.overrideSprite = result.OriginalSprite;
					((Graphic)result.Image).color = result.OriginalColor;
					((Graphic)result.Image).SetAllDirty();
				}
				else if (result.IsRaw && (Object)(object)result.RawImage != (Object)null && (Object)(object)((Component)result.RawImage).gameObject != (Object)null)
				{
					result.RawImage.texture = null;
					((Graphic)result.RawImage).color = new Color(1f, 1f, 1f, 0f);
					((Behaviour)result.RawImage).enabled = false;
					((Graphic)result.RawImage).SetAllDirty();
				}
				else if (!result.IsRaw && (Object)(object)result.Image != (Object)null && (Object)(object)((Component)result.Image).gameObject != (Object)null)
				{
					result.Image.sprite = null;
					result.Image.overrideSprite = null;
					((Graphic)result.Image).color = new Color(1f, 1f, 1f, 0f);
					((Behaviour)result.Image).enabled = false;
					((Graphic)result.Image).SetAllDirty();
				}
			}
		}

		private static bool Approximately(float a, float b)
		{
			return Mathf.Abs(a - b) <= 0.001f;
		}

		internal static bool IsFullscreenLike(RectTransform rt)
		{
			//IL_000c: 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_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)rt == (Object)null)
			{
				return false;
			}
			bool num = Approximately(rt.anchorMin.x, 0f) && Approximately(rt.anchorMin.y, 0f) && Approximately(rt.anchorMax.x, 1f) && Approximately(rt.anchorMax.y, 1f);
			bool flag = Approximately(rt.offsetMin.x, 0f) && Approximately(rt.offsetMin.y, 0f) && Approximately(rt.offsetMax.x, 0f) && Approximately(rt.offsetMax.y, 0f);
			return num && flag;
		}

		internal static string GetHierarchyPath(Transform transform)
		{
			if ((Object)(object)transform == (Object)null)
			{
				return "<null>";
			}
			List<string> list = new List<string>();
			Transform val = transform;
			while ((Object)(object)val != (Object)null)
			{
				list.Insert(0, ((Object)val).name);
				val = val.parent;
			}
			return string.Join("/", list.ToArray());
		}

		internal static int CalculateConnectedWorldLoadingImageScore(Image img)
		{
			//IL_043c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0441: Unknown result type (might be due to invalid IL or missing references)
			//IL_0453: Unknown result type (might be due to invalid IL or missing references)
			//IL_0458: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)((img != null) ? ((Component)img).gameObject : null) == (Object)null)
			{
				return int.MinValue;
			}
			string text = ((Object)((Component)img).gameObject).name ?? string.Empty;
			text = text.ToLowerInvariant();
			string text2 = GetHierarchyPath(((Component)img).transform).ToLowerInvariant();
			string text3 = (((Object)(object)img.sprite != (Object)null) ? (((Object)img.sprite).name ?? string.Empty).ToLowerInvariant() : string.Empty);
			if (!text2.Contains("loadinggui"))
			{
				return int.MinValue;
			}
			if (text2.Contains("popupblockingbackground") || text2.Contains("unifiedpopup") || text2.Contains("achievementpopup") || text2.Contains("achievementui") || text2.Contains("editguild") || text2.Contains("createguild") || text2.Contains("searchguild") || text2.Contains("guildmanagementui") || text2.Contains("applicationsui") || text2.Contains("noguild") || text2.Contains("discord") || text2.Contains("_console(clone)") || text2.Contains("/_console") || text2.Contains("logoutput") || text2.Contains("serveroptions") || text2.Contains("connectionfailed") || text2.Contains("managesavesmenu") || text2.Contains("removecharacterdialog") || text2.Contains("pleasewait"))
			{
				return int.MinValue;
			}
			if (!text.Contains("crosshair") && !text.Contains("healthicon") && !text.Contains("foodicon") && !text.Contains("windicon") && !text.Contains("mounticon") && !text.Contains("player_marker") && !text.Contains("ship_marker") && !text.Contains("wind_marker"))
			{
				switch (text)
				{
				case "backgroundback":
				case "buttonclose":
				case "button":
				case "border":
				case "bkg":
				case "bar":
				case "darken":
				case "handle":
				case "separator":
					break;
				default:
				{
					if (text2.Contains("/enemyhud/") || text2.Contains("/inventory_screen/") || text2.Contains("/statuseffects/") || text2.Contains("/keyhints/") || text2.Contains("/buildhud/") || text2.Contains("/shiphud/controls/") || text2.Contains("/crosshair/") || text2.Contains("/guardianpower/"))
					{
						return int.MinValue;
					}
					int num = 0;
					if (text == "screen")
					{
						num += 5000;
					}
					if (text2.EndsWith("/hud/screen"))
					{
						num += 5000;
					}
					if (text2.Contains("/hud/screen"))
					{
						num += 3000;
					}
					if (text2.Contains("loadinggui"))
					{
						num += 300;
					}
					if (text2.Contains("pixelfix"))
					{
						num += 40;
					}
					if (text2.Contains("/hud/"))
					{
						num += 150;
					}
					if (text2.Contains("/ingamegui/"))
					{
						num += 50;
					}
					if (text == "background")
					{
						num += 180;
					}
					if (text.Contains("background"))
					{
						num += 120;
					}
					if (text3.Contains("background"))
					{
						num += 60;
					}
					if (text.Contains("image"))
					{
						num += 20;
					}
					if (((Behaviour)img).enabled)
					{
						num += 20;
					}
					if (((Component)img).gameObject.activeInHierarchy)
					{
						num += 60;
					}
					if ((Object)(object)((Graphic)img).canvasRenderer != (Object)null && ((Graphic)img).canvasRenderer.GetAlpha() > 0.01f)
					{
						num += 40;
					}
					RectTransform rectTransform = ((Graphic)img).rectTransform;
					if ((Object)(object)rectTransform != (Object)null)
					{
						Rect rect = rectTransform.rect;
						float num2 = Mathf.Abs(((Rect)(ref rect)).width);
						rect = rectTransform.rect;
						float num3 = Mathf.Abs(((Rect)(ref rect)).height);
						float num4 = num2 * num3;
						if (num4 < 200000f)
						{
							return int.MinValue;
						}
						if (num4 > 300000f)
						{
							num += 60;
						}
						if (num4 > 500000f)
						{
							num += 120;
						}
						if (num4 > 1000000f)
						{
							num += 220;
						}
						if (num4 > 1800000f)
						{
							num += 320;
						}
						if (num2 >= (float)Screen.width * 0.7f)
						{
							num += 80;
						}
						if (num3 >= (float)Screen.height * 0.7f)
						{
							num += 80;
						}
						if (num2 >= (float)Screen.width * 0.9f)
						{
							num += 100;
						}
						if (num3 >= (float)Screen.height * 0.9f)
						{
							num += 100;
						}
						if (IsFullscreenLike(rectTransform))
						{
							num += 400;
						}
					}
					return num;
				}
				}
			}
			return int.MinValue;
		}

		internal static int CalculateConnectedWorldLoadingRawImageScore(RawImage raw)
		{
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e2: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)((raw != null) ? ((Component)raw).gameObject : null) == (Object)null)
			{
				return int.MinValue;
			}
			string text = (((Object)((Component)raw).gameObject).name ?? string.Empty).ToLowerInvariant();
			string text2 = GetHierarchyPath(((Component)raw).transform).ToLowerInvariant();
			if (!text2.Contains("loadinggui"))
			{
				return int.MinValue;
			}
			if (text2.Contains("popupblockingbackground") || text2.Contains("unifiedpopup") || text2.Contains("achievementpopup") || text2.Contains("achievementui") || text2.Contains("editguild") || text2.Contains("createguild") || text2.Contains("searchguild") || text2.Contains("guildmanagementui") || text2.Contains("applicationsui") || text2.Contains("noguild") || text2.Contains("discord") || text2.Contains("_console(clone)") || text2.Contains("/_console") || text2.Contains("logoutput") || text2.Contains("serveroptions") || text2.Contains("connectionfailed") || text2.Contains("managesavesmenu") || text2.Contains("removecharacterdialog") || text2.Contains("pleasewait"))
			{
				return int.MinValue;
			}
			if (text2.Contains("/enemyhud/") || text2.Contains("/inventory_screen/") || text2.Contains("/statuseffects/") || text2.Contains("/keyhints/") || text2.Contains("/buildhud/") || text2.Contains("/shiphud/controls/") || text2.Contains("/crosshair/") || text2.Contains("/guardianpower/"))
			{
				return int.MinValue;
			}
			int num = 0;
			if (text == "screen")
			{
				num += 5000;
			}
			if (text2.EndsWith("/hud/screen"))
			{
				num += 5000;
			}
			if (text2.Contains("/hud/screen"))
			{
				num += 3000;
			}
			if (text2.Contains("loadinggui"))
			{
				num += 300;
			}
			if (text2.Contains("pixelfix"))
			{
				num += 40;
			}
			if (text2.Contains("/hud/"))
			{
				num += 150;
			}
			if (text == "background")
			{
				num += 180;
			}
			if (text.Contains("background"))
			{
				num += 120;
			}
			if (text.Contains("image"))
			{
				num += 20;
			}
			if (((Behaviour)raw).enabled)
			{
				num += 20;
			}
			if (((Component)raw).gameObject.activeInHierarchy)
			{
				num += 60;
			}
			RectTransform rectTransform = ((Graphic)raw).rectTransform;
			if ((Object)(object)rectTransform != (Object)null)
			{
				Rect rect = rectTransform.rect;
				float num2 = Mathf.Abs(((Rect)(ref rect)).width);
				rect = rectTransform.rect;
				float num3 = Mathf.Abs(((Rect)(ref rect)).height);
				float num4 = num2 * num3;
				if (num4 < 200000f)
				{
					return int.MinValue;
				}
				if (num4 > 300000f)
				{
					num += 60;
				}
				if (num4 > 500000f)
				{
					num += 120;
				}
				if (num4 > 1000000f)
				{
					num += 220;
				}
				if (num4 > 1800000f)
				{
					num += 320;
				}
				if (num2 >= (float)Screen.width * 0.7f)
				{
					num += 80;
				}
				if (num3 >= (float)Screen.height * 0.7f)
				{
					num += 80;
				}
				if (num2 >= (float)Screen.width * 0.9f)
				{
					num += 100;
				}
				if (num3 >= (float)Screen.height * 0.9f)
				{
					num += 100;
				}
				if (IsFullscreenLike(rectTransform))
				{
					num += 400;
				}
			}
			return num;
		}

		internal static void StretchToFullscreen(RectTransform rt)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)rt == (Object)null))
			{
				rt.anchorMin = Vector2.zero;
				rt.anchorMax = Vector2.one;
				rt.pivot = new Vector2(0.5f, 0.5f);
				rt.offsetMin = Vector2.zero;
				rt.offsetMax = Vector2.zero;
				rt.anchoredPosition = Vector2.zero;
				((Transform)rt).localScale = Vector3.one;
				((Transform)rt).localRotation = Quaternion.identity;
			}
		}
	}
	internal static class MenuAmbientMute
	{
		private struct MutedSource
		{
			public AudioSource Source;

			public float Volume;

			public bool Mute;
		}

		private static ConfigEntry<bool>? _muteAmbient;

		private static bool _resolved;

		private static FieldInfo? _oceanSource;

		private static FieldInfo? _windSource;

		private static FieldInfo? _ambientLoopSource;

		private static readonly List<MutedSource> _muted = new List<MutedSource>();

		private static readonly HashSet<int> _mutedIds = new HashSet<int>();

		internal static void BindConfig(ConfigFile config)
		{
			if (_muteAmbient != null)
			{
				_muteAmbient.SettingChanged -= OnMuteSettingChanged;
			}
			_muteAmbient = config.Bind<bool>("Main Menu", "MuteAmbient", true, "Mute ocean, wind, and looping biome ambient on the start menu. Button clicks still follow the Effects slider. Off restores vanilla menu ambient.");
			TryMigrateMuteAmbientFromRetiredSection(config);
			_muteAmbient.SettingChanged += OnMuteSettingChanged;
		}

		private static void TryMigrateMuteAmbientFromRetiredSection(ConfigFile config)
		{
			if (_muteAmbient != null)
			{
				string configFilePath = config.ConfigFilePath;
				if (!string.IsNullOrEmpty(configFilePath) && File.Exists(configFilePath) && !TryReadIniBool(configFilePath, "Main Menu", "MuteAmbient", out var _) && TryReadIniBool(configFilePath, "Menu Scenery", "MuteAmbient", out var value2))
				{
					_muteAmbient.Value = value2;
				}
			}
		}

		private static bool TryReadIniBool(string path, string section, string key, out bool value)
		{
			value = false;
			string[] array;
			try
			{
				array = File.ReadAllLines(path);
			}
			catch
			{
				return false;
			}
			bool flag = false;
			string b = "[" + section + "]";
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length == 0 || text[0] == '#' || text[0] == ';')
				{
					continue;
				}
				if (text[0] == '[')
				{
					flag = string.Equals(text, b, StringComparison.Ordinal);
				}
				else
				{
					if (!flag || !text.StartsWith(key, StringComparison.Ordinal))
					{
						continue;
					}
					int num = text.IndexOf('=');
					if (num > 0 && string.Equals(text.Substring(0, num).Trim(), key, StringComparison.Ordinal))
					{
						string text2 = text.Substring(num + 1).Trim();
						int num2 = text2.IndexOfAny(new char[4] { ' ', '\t', '#', ';' });
						if (num2 > 0)
						{
							text2 = text2.Substring(0, num2);
						}
						return bool.TryParse(text2, out value);
					}
				}
			}
			return false;
		}

		internal static void Shutdown()
		{
			if (_muteAmbient != null)
			{
				_muteAmbient.SettingChanged -= OnMuteSettingChanged;
			}
			Restore();
		}

		internal static bool ShouldMute()
		{
			if (CustomMainMenuPlugin.ModEnabled != null && CustomMainMenuPlugin.ModEnabled.Value && CustomMainMenuPlugin.MainMenuActive)
			{
				if (_muteAmbient != null)
				{
					return _muteAmbient.Value;
				}
				return true;
			}
			return false;
		}

		internal static bool TrySilenceAndSkipVanilla()
		{
			if (!ShouldMute())
			{
				return false;
			}
			SilenceAudioManAmbientSources();
			return true;
		}

		internal static void Apply()
		{
			if (!ShouldMute())
			{
				Restore();
				return;
			}
			SilenceAudioManAmbientSources();
			MuteSceneAmbientOnce();
		}

		internal static void Restore()
		{
			for (int i = 0; i < _muted.Count; i++)
			{
				MutedSource mutedSource = _muted[i];
				if (!((Object)(object)mutedSource.Source == (Object)null))
				{
					mutedSource.Source.volume = mutedSource.Volume;
					mutedSource.Source.mute = mutedSource.Mute;
				}
			}
			_muted.Clear();
			_mutedIds.Clear();
		}

		private static void OnMuteSettingChanged(object sender, EventArgs e)
		{
			Apply();
		}

		private static void EnsureResolved()
		{
			if (!_resolved)
			{
				_resolved = true;
				Type? typeFromHandle = typeof(AudioMan);
				_oceanSource = AccessTools.Field(typeFromHandle, "m_oceanAmbientSource");
				_windSource = AccessTools.Field(typeFromHandle, "m_windLoopSource");
				_ambientLoopSource = AccessTools.Field(typeFromHandle, "m_ambientLoopSource");
			}
		}

		private static void SilenceAudioManAmbientSources()
		{
			try
			{
				AudioMan instance = AudioMan.instance;
				if (!((Object)(object)instance == (Object)null))
				{
					EnsureResolved();
					object? obj = _oceanSource?.GetValue(instance);
					RememberAndSilence((AudioSource?)((obj is AudioSource) ? obj : null));
					object? obj2 = _windSource?.GetValue(instance);
					RememberAndSilence((AudioSource?)((obj2 is AudioSource) ? obj2 : null));
					object? obj3 = _ambientLoopSource?.GetValue(instance);
					RememberAndSilence((AudioSource?)((obj3 is AudioSource) ? obj3 : null));
				}
			}
			catch (Exception ex)
			{
				CustomMainMenuPlugin.LogInfo("Menu ambient mute skipped: " + ex.Message);
			}
		}

		private static void MuteSceneAmbientOnce()
		{
			try
			{
				AudioMan instance = AudioMan.instance;
				AudioMixerGroup gui = (((Object)(object)instance != (Object)null) ? instance.m_guiMixer : null);
				AudioMixerGroup ambient = (((Object)(object)instance != (Object)null) ? instance.m_ambientMixer : null);
				AudioMixerGroup music = (((Object)(object)MusicMan.instance != (Object)null) ? MusicMan.instance.m_musicMixer : null);
				AudioSource[] array = Object.FindObjectsByType<AudioSource>((FindObjectsInactive)1, (FindObjectsSortMode)0);
				int num = 0;
				foreach (AudioSource src in array)
				{
					if (ShouldMuteSceneSource(src, gui, ambient, music) && RememberAndSilence(src))
					{
						num++;
					}
				}
				if (num > 0)
				{
					CustomMainMenuPlugin.LogInfo($"Menu ambient muted ({num} scene source(s)).");
				}
			}
			catch (Exception ex)
			{
				CustomMainMenuPlugin.LogInfo("Menu ambient scene mute skipped: " + ex.Message);
			}
		}

		private static bool ShouldMuteSceneSource(AudioSource? src, AudioMixerGroup? gui, AudioMixerGroup? ambient, AudioMixerGroup? music)
		{
			if ((Object)(object)src == (Object)null)
			{
				return false;
			}
			if (((Object)((Component)src).gameObject).name == "CustomMainMenuMusicAudio")
			{
				return false;
			}
			AudioMixerGroup outputAudioMixerGroup = src.outputAudioMixerGroup;
			if (IsGuiOrMusicGroup(outputAudioMixerGroup, gui, music))
			{
				return false;
			}
			if ((Object)(object)ambient != (Object)null && (Object)(object)outputAudioMixerGroup == (Object)(object)ambient)
			{
				return true;
			}
			if ((Object)(object)outputAudioMixerGroup != (Object)null && GroupNameContains(outputAudioMixerGroup, "Ambient"))
			{
				return true;
			}
			if (!src.loop)
			{
				if (src.isPlaying)
				{
					return src.spatialBlend > 0.05f;
				}
				return false;
			}
			return true;
		}

		private static bool IsGuiOrMusicGroup(AudioMixerGroup? group, AudioMixerGroup? gui, AudioMixerGroup? music)
		{
			if ((Object)(object)group == (Object)null)
			{
				return false;
			}
			if ((Object)(object)gui != (Object)null && (Object)(object)group == (Object)(object)gui)
			{
				return true;
			}
			if ((Object)(object)music != (Object)null && (Object)(object)group == (Object)(object)music)
			{
				return true;
			}
			if (!GroupNameContains(group, "GUI"))
			{
				return GroupNameContains(group, "Music");
			}
			return true;
		}

		private static bool GroupNameContains(AudioMixerGroup group, string token)
		{
			string name = ((Object)group).name;
			if (!string.IsNullOrEmpty(name))
			{
				return name.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}

		private static bool RememberAndSilence(AudioSource? src)
		{
			if ((Object)(object)src == (Object)null)
			{
				return false;
			}
			int instanceID = ((Object)src).GetInstanceID();
			if (!_mutedIds.Add(instanceID))
			{
				src.volume = 0f;
				src.mute = true;
				return false;
			}
			_muted.Add(new MutedSource
			{
				Source = src,
				Volume = src.volume,
				Mute = src.mute
			});
			src.volume = 0f;
			src.mute = true;
			return true;
		}
	}
	internal static class MenuAtmosphere
	{
		private enum ApplyMode
		{
			None,
			StartSceneFallback
		}

		internal const float DefaultNightTimeFraction = 0.875f;

		private const float FallbackSunAngle = 45f;

		private static readonly Color FallbackFogColor = new Color(0.047f, 0.165f, 0.196f, 1f);

		private static readonly Color FallbackAmbientLight = new Color(0.191f, 0.269f, 0.36f, 1f);

		private static readonly Color FallbackSunColor = new Color(0.337f, 0.729f, 0.714f, 1f);

		private const float FallbackFogDensity = 0.08f;

		private const float FallbackSunIntensity = 0.05f;

		private const float ValheimLitSunIntensity = 0.7f;

		private static ApplyMode _mode;

		private s