Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of CustomMainMenu v1.0.0
plugins/CustomMainMenu.dll
Decompiled 3 days ago
The result has been truncated due to the large size, download it to view full contents!
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 BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.Networking; using UnityEngine.Rendering; using UnityEngine.UI; [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, and Discord link via BepInEx config folder.")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("CustomMainMenu")] [assembly: AssemblyTitle("CustomMainMenu")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.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 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.0.0")] public sealed class CustomMainMenuPlugin : BaseUnityPlugin { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static UnityAction <>9__72_0; internal void <CreateDiscordPanel>b__72_0() { if (!DiscordPanelVisibility.TryOpenInviteUrl()) { LogWarn("Discord invite URL is missing or invalid in config."); } } } public const string ModGuid = "rdmods.custommainmenu"; public const string ModName = "Custom Main Menu"; public const string AssetFolderName = "CustomMainMenu"; public const string LoadingArtFolderName = "LoadingArt"; public const int LoadingArtMaxSlot = 12; public const string DiscordTitleText = "Need help? Join Discord!"; public const string DiscordButtonText = "Click here to join Discord!"; 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? _menuAtmosphereCoroutine; private Coroutine? _menuAtmosphereApplyCoroutine; private static GameObject? _discordPanel; private Coroutine? _discordLogoCoroutine; private static Image? _discordLogoImage; private static readonly HashSet<string> NeverHide = new HashSet<string>(StringComparer.Ordinal) { "startgui", "worldpanel", "startgame", "topleft", "topright", "menu", "joinpanel", "panel", "tooltips" }; 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 void SetDiscordPanelRoot(GameObject? panel) { _discordPanel = panel; } private void Awake() { //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown Instance = this; ModLog = ((BaseUnityPlugin)this).Logger; MenuMusicFadeCommittedForSession = 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."); DiscordPanelVisibility.BindConfig(((BaseUnityPlugin)this).Config); MenuScenery.BindConfig(((BaseUnityPlugin)this).Config); ((BaseUnityPlugin)this).Config.Save(); if (!ModEnabled.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Custom Main Menu is disabled in config."); return; } EnsureAssetDirectories(); _harmony = new Harmony("rdmods.custommainmenu"); _harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Custom Main Menu loaded. Asset root: " + GetAssetRootPath())); } private void OnDestroy() { 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 (_menuAtmosphereCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_menuAtmosphereCoroutine); _menuAtmosphereCoroutine = null; } if (_menuAtmosphereApplyCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_menuAtmosphereApplyCoroutine); _menuAtmosphereApplyCoroutine = null; } MenuAtmosphere.Clear(); MenuScenery.Clear(); 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 (Instance?._enableLogging != null && Instance._enableLogging.Value) { 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); } } internal static string GetAssetRootPath() { return Path.Combine(Paths.ConfigPath, "CustomMainMenu"); } internal static string GetLoadingArtFolder() { return Path.Combine(GetAssetRootPath(), "LoadingArt"); } internal static string GetLogoPath() { return Path.Combine(GetAssetRootPath(), "logo.png"); } internal static string GetDiscordLogoPath() { return Path.Combine(GetAssetRootPath(), "discordlogo.png"); } internal static string GetMusicPath() { return Path.Combine(GetAssetRootPath(), "mainmenu.ogg"); } internal static string? GetRandomLoadingArtPath() { string loadingArtFolder = GetLoadingArtFolder(); if (!Directory.Exists(loadingArtFolder)) { return null; } string result = null; int num = 0; for (int i = 1; i <= 12; i++) { string text = Path.Combine(loadingArtFolder, $"art{i}.png"); 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)); } } internal static void OnMainMenuOpened(FejdStartup fejd) { MainMenuActive = true; DiscordPanelVisibility.ResetSessionState(); MenuAtmosphere.ResetForMenuSession(); MenuScenery.ResetForMenuSession(); MenuScenery.ScheduleApplyStaging(fejd); StopMusicManWorldMusicForMainMenu(); if ((Object)(object)Instance == (Object)null) { MenuAtmosphere.Apply(); return; } if (Instance._menuAtmosphereApplyCoroutine != null) { ((MonoBehaviour)Instance).StopCoroutine(Instance._menuAtmosphereApplyCoroutine); Instance._menuAtmosphereApplyCoroutine = null; } Instance._menuAtmosphereApplyCoroutine = ((MonoBehaviour)fejd).StartCoroutine(MenuAtmosphere.ApplyWhenReady()); if (Instance._menuAtmosphereCoroutine != null) { ((MonoBehaviour)Instance).StopCoroutine(Instance._menuAtmosphereCoroutine); Instance._menuAtmosphereCoroutine = null; } Instance._menuAtmosphereCoroutine = ((MonoBehaviour)Instance).StartCoroutine(MaintainMenuAtmosphereWhileOnMainMenu()); } internal static void LogSceneryClear(string reason) { LogInfo("Menu scenery cleared (" + reason + ")."); } internal static void OnWorldLoadCommitted() { LoadingScreens.StopAllWatchers("world load committed"); DiscordPanelVisibility.Hide("world load committed"); MenuAtmosphere.Clear(); MenuScenery.Clear(); LogSceneryClear("world load"); if (Instance?._menuAtmosphereCoroutine != null) { ((MonoBehaviour)Instance).StopCoroutine(Instance._menuAtmosphereCoroutine); Instance._menuAtmosphereCoroutine = null; } 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 IEnumerator MaintainMenuAtmosphereWhileOnMainMenu() { WaitForSecondsRealtime wait = new WaitForSecondsRealtime(0.25f); while (MainMenuActive && (Object)(object)Instance != (Object)null) { MenuAtmosphere.MaintainAppliedState(); yield return wait; } if ((Object)(object)Instance != (Object)null) { Instance._menuAtmosphereCoroutine = null; } } internal static IEnumerator MuteVanillaMenuMusicOnceDelayed() { yield return (object)new WaitForSecondsRealtime(0.5f); if ((Object)(object)Instance != (Object)null && MainMenuActive) { MuteVanillaMenuMusicNow(); } } private static void MuteVanillaMenuMusicNow() { try { if (!(Resources.FindObjectsOfTypeAll(typeof(AudioSource)) is AudioSource[] array)) { return; } AudioSource[] array2 = array; foreach (AudioSource val in array2) { if (!((Object)(object)((val != null) ? ((Component)val).gameObject : null) == (Object)null) && !((Object)(object)val == (Object)(object)Instance?._menuMusicSource)) { string text = ((Object)((Component)val).gameObject).name.ToLowerInvariant(); string text2 = (((Object)(object)val.clip != (Object)null) ? ((Object)val.clip).name.ToLowerInvariant() : string.Empty); string text3 = LoadingScreens.GetHierarchyPath(((Component)val).transform).ToLowerInvariant(); if ((text3.Contains("fejd") || text3.Contains("menu") || text3.Contains("main") || text.Contains("music") || text.Contains("audio") || text2.Contains("menu") || text2.Contains("theme") || text2.Contains("music")) && (val.isPlaying || !(val.volume <= 0.001f))) { val.volume = 0f; val.Stop(); } } } } catch (Exception ex) { ManualLogSource? modLog = ModLog; if (modLog != null) { modLog.LogError((object)ex); } } } internal static IEnumerator HideUnwantedMainMenuUiDelayed() { yield return (object)new WaitForSecondsRealtime(0.5f); HideMenuClutterOnce(); } private static void HideMenuClutterOnce() { FejdStartup val = Object.FindFirstObjectByType<FejdStartup>(); if ((Object)(object)val == (Object)null) { return; } Transform[] componentsInChildren = ((Component)val).GetComponentsInChildren<Transform>(true); for (int i = 0; i < componentsInChildren.Length; i++) { GameObject gameObject = ((Component)componentsInChildren[i]).gameObject; string text = (((Object)gameObject).name ?? string.Empty).ToLowerInvariant(); if (!NeverHide.Contains(text)) { string lowerOwn = GetOwnText(gameObject).ToLowerInvariant(); if (ShouldHideUi(text, lowerOwn)) { gameObject.SetActive(false); } } } } private static bool ShouldHideUi(string lowerName, string lowerOwn) { 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 true; } 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(); } internal static IEnumerator ReplaceLogoDelayed() { yield return (object)new WaitForSecondsRealtime(0.75f); FejdStartup val = Object.FindFirstObjectByType<FejdStartup>(); if ((Object)(object)val == (Object)null || !File.Exists(GetLogoPath())) { yield break; } Image val2 = null; int num = int.MinValue; Image[] componentsInChildren = ((Component)val).GetComponentsInChildren<Image>(true); foreach (Image val3 in componentsInChildren) { if (!((Object)(object)val3 == (Object)null)) { int num2 = ScoreLogo(val3); if (num2 > num) { num = num2; val2 = val3; } } } if ((Object)(object)val2 != (Object)null && num >= 50) { Sprite val4 = LoadSpriteFromDisk(GetLogoPath()); if ((Object)(object)val4 != (Object)null) { ApplyLogo(val2, val4); LogInfo($"Logo applied (score {num})."); } } } private static int ScoreLogo(Image img) { //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: 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("valheim")) { num += 80; } 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; } if (((Transform)rectTransform).position.y > (float)Screen.height * 0.45f) { 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 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; } } 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)) { 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? FindBestVisibleMainMenuButton(FejdStartup startup) { //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)startup == (Object)null) { return null; } Button result = null; int num = int.MinValue; Button[] componentsInChildren = ((Component)startup).GetComponentsInChildren<Button>(true); foreach (Button val in componentsInChildren) { if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy) { continue; } string text = GetButtonText(((Component)val).gameObject).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("start") || text2.Contains("start")) { num2 += 150; } if (text.Contains("play")) { num2 += 120; } RectTransform component = ((Component)val).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 = val; } } 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() { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_0261: Expected O, but got Unknown //IL_02b0: Unknown result type (might be due to invalid IL or missing references) //IL_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_02e5: Unknown result type (might be due to invalid IL or missing references) //IL_02f8: Unknown result type (might be due to invalid IL or missing references) //IL_02ff: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) //IL_0315: Unknown result type (might be due to invalid IL or missing references) //IL_031a: Unknown result type (might be due to invalid IL or missing references) //IL_031b: Unknown result type (might be due to invalid IL or missing references) //IL_0322: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Unknown result type (might be due to invalid IL or missing references) //IL_03d3: Unknown result type (might be due to invalid IL or missing references) //IL_03dd: Expected O, but got Unknown //IL_03f8: Unknown result type (might be due to invalid IL or missing references) //IL_03fd: Unknown result type (might be due to invalid IL or missing references) //IL_0403: Expected O, but got Unknown try { FejdStartup val = Object.FindFirstObjectByType<FejdStartup>(); if ((Object)(object)_discordPanel != (Object)null) { DiscordPanelVisibility.Refresh(val, "FejdStartup.Start (panel reuse)"); return; } Canvas val2 = Object.FindFirstObjectByType<Canvas>(); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || (Object)(object)Instance == (Object)null) { return; } _discordPanel = new GameObject("CustomMainMenuDiscordPanel"); _discordPanel.transform.SetParent(((Component)val2).transform, false); RectTransform obj = _discordPanel.AddComponent<RectTransform>(); obj.anchorMin = new Vector2(1f, 0f); obj.anchorMax = new Vector2(1f, 0f); obj.pivot = new Vector2(1f, 0f); obj.anchoredPosition = new Vector2(-36f, 105f); obj.sizeDelta = new Vector2(328f, 360f); VerticalLayoutGroup obj2 = _discordPanel.AddComponent<VerticalLayoutGroup>(); ((LayoutGroup)obj2).childAlignment = (TextAnchor)4; ((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = false; ((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)obj2).spacing = 16f; _discordPanel.AddComponent<ContentSizeFitter>().verticalFit = (FitMode)2; TextMeshProUGUI val3 = FindBestMenuTmpText(val); GameObject val4 = new GameObject("DiscordTitle", new Type[1] { typeof(RectTransform) }); val4.transform.SetParent(_discordPanel.transform, false); NormalizeRectForLayoutGroup(val4.GetComponent<RectTransform>()); LayoutElement obj3 = val4.AddComponent<LayoutElement>(); obj3.flexibleWidth = 1f; obj3.preferredWidth = 300f; obj3.preferredHeight = 90f; TextMeshProUGUI val5 = val4.AddComponent<TextMeshProUGUI>(); ((TMP_Text)val5).richText = false; ((TMP_Text)val5).text = "Need help? Join Discord!"; ((TMP_Text)val5).horizontalAlignment = (HorizontalAlignmentOptions)2; ((TMP_Text)val5).verticalAlignment = (VerticalAlignmentOptions)512; ((TMP_Text)val5).textWrappingMode = (TextWrappingModes)1; ((TMP_Text)val5).overflowMode = (TextOverflowModes)0; ((TMP_Text)val5).margin = Vector4.zero; ((TMP_Text)val5).enableAutoSizing = false; ((Graphic)val5).raycastTarget = false; if ((Object)(object)val3 != (Object)null) { ((TMP_Text)val5).font = ((TMP_Text)val3).font; ((TMP_Text)val5).fontSharedMaterial = ((TMP_Text)val3).fontSharedMaterial; ((TMP_Text)val5).fontSize = Mathf.Clamp(((TMP_Text)val3).fontSize - 1f, 16f, 28f); ((Graphic)val5).color = ((Graphic)val3).color; } else { ((TMP_Text)val5).fontSize = 22f; ((Graphic)val5).color = new Color(0.93f, 0.79f, 0.42f); } GameObject val6 = new GameObject("DiscordLogo"); val6.transform.SetParent(_discordPanel.transform, false); LayoutElement obj4 = val6.AddComponent<LayoutElement>(); obj4.preferredHeight = 150f; obj4.preferredWidth = 300f; _discordLogoImage = val6.AddComponent<Image>(); _discordLogoImage.type = (Type)0; ((Graphic)_discordLogoImage).color = Color.white; ((Graphic)_discordLogoImage).material = null; _discordLogoImage.preserveAspect = true; ((Graphic)_discordLogoImage).raycastTarget = false; GameObject val7 = new GameObject("DiscordGlyph"); val7.transform.SetParent(val6.transform, false); RectTransform obj5 = val7.AddComponent<RectTransform>(); obj5.anchorMin = Vector2.zero; obj5.anchorMax = Vector2.one; Vector2 offsetMin = (obj5.offsetMax = Vector2.zero); obj5.offsetMin = offsetMin; Text obj6 = val7.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; Button val8 = FindBestVisibleMainMenuButton(val); if ((Object)(object)val8 != (Object)null) { GameObject val9 = Object.Instantiate<GameObject>(((Component)val8).gameObject, _discordPanel.transform, false); LayoutElement obj7 = val9.GetComponent<LayoutElement>() ?? val9.AddComponent<LayoutElement>(); obj7.preferredWidth = 300f; obj7.preferredHeight = 46f; Button component = val9.GetComponent<Button>(); if ((Object)(object)component != (Object)null) { component.onClick = new ButtonClickedEvent(); ButtonClickedEvent onClick = component.onClick; object obj8 = <>c.<>9__72_0; if (obj8 == null) { UnityAction val10 = delegate { if (!DiscordPanelVisibility.TryOpenInviteUrl()) { LogWarn("Discord invite URL is missing or invalid in config."); } }; <>c.<>9__72_0 = val10; obj8 = (object)val10; } ((UnityEvent)onClick).AddListener((UnityAction)obj8); SetButtonText(val9, "Click here to join Discord!"); } } Instance._discordLogoCoroutine = ((MonoBehaviour)Instance).StartCoroutine(Instance.LoadDiscordLogoDelayed()); DiscordPanelVisibility.RegisterPanel(_discordPanel); DiscordPanelVisibility.Refresh(val, "Discord panel created"); LogInfo("Discord panel ready."); } catch (Exception ex) { ManualLogSource? modLog = ModLog; if (modLog != null) { modLog.LogError((object)("Discord panel failed: " + ex)); } } } 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 StartMenuMusic() { if (!((Object)(object)Instance == (Object)null)) { 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; menuMusicSource.volume = 0.55f; 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; } } 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; } } 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._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; } AudioSource src = plug._menuMusicSource; float v0 = src.volume; float t = 0f; while (t < seconds && (Object)(object)src != (Object)null) { t += Time.unscaledDeltaTime; src.volume = Mathf.Lerp(v0, 0f, Mathf.Clamp01(t / seconds)); 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", string.Empty, "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 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 void SyncIfDrifted(FejdStartup? fejd) { if (!IsGatingEnabled() || !CustomMainMenuPlugin.MainMenuActive) { return; } GameObject discordPanelRoot = CustomMainMenuPlugin.DiscordPanelRoot; if (!((Object)(object)discordPanelRoot == (Object)null)) { bool flag = ComputeShouldBeVisible(fejd); if (_lastAppliedVisible != flag) { ApplyVisible(discordPanelRoot, flag, "FejdStartup.LateUpdate (visibility drift)"); } } } private static bool ComputeShouldBeVisible(FejdStartup? fejd) { if (!CustomMainMenuPlugin.MainMenuActive) { return false; } if (!IsGatingEnabled()) { return true; } if ((Object)(object)fejd == (Object)null || (Object)(object)fejd.m_mainMenu == (Object)null) { return false; } return fejd.m_mainMenu.activeInHierarchy; } 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 Image? Image; internal RawImage? RawImage; internal int Score; internal string Path; internal string ObjectName; } private const float PostSceneDelaySeconds = 0f; private const float SearchIntervalSeconds = 0.5f; private const float MaxLoadWaitSeconds = 2400f; private const float MaintainArtIntervalSeconds = 2f; private const int MinimumValidScore = 300; private const float LoadingFadeOutSeconds = 0.6f; private static Coroutine? _cleanupCoroutine; private static Coroutine? _forceCoroutine; private static Coroutine? _watcherCoroutine; internal static volatile bool WatcherRunning; internal static volatile bool LoadingArtSessionActive; internal static void ResetForMainMenu() { StopAllWatchers("main menu reset"); LoadingArtSessionActive = false; } internal static void StopAllWatchers(string reason) { if ((Object)(object)CustomMainMenuPlugin.Instance == (Object)null) { WatcherRunning = false; _watcherCoroutine = null; _forceCoroutine = null; _cleanupCoroutine = null; return; } if (_watcherCoroutine != null) { ((MonoBehaviour)CustomMainMenuPlugin.Instance).StopCoroutine(_watcherCoroutine); _watcherCoroutine = null; } if (_forceCoroutine != null) { ((MonoBehaviour)CustomMainMenuPlugin.Instance).StopCoroutine(_forceCoroutine); _forceCoroutine = null; } if (_cleanupCoroutine != null) { ((MonoBehaviour)CustomMainMenuPlugin.Instance).StopCoroutine(_cleanupCoroutine); _cleanupCoroutine = null; } if (WatcherRunning || LoadingArtSessionActive) { LogLoading("Loading watcher stopped (" + reason + ")."); } WatcherRunning = false; LoadingArtSessionActive = false; } internal static void TryStartLoadingScreenWatcher(string trigger) { if (!CustomMainMenuPlugin.EnableCustomLoadingScreens || (Object)(object)CustomMainMenuPlugin.Instance == (Object)null) { LogLoading("Loading watcher skipped (" + trigger + "): custom loading screens disabled or plugin missing."); return; } if (CustomMainMenuPlugin.MainMenuActive) { LogLoading("Loading watcher deferred (" + trigger + "): still on Fejd main menu (world select / UI)."); return; } if (WatcherRunning || LoadingArtSessionActive) { LogLoading("Loading watcher skipped (" + trigger + "): already running."); return; } LogLoading("Loading watcher started (" + trigger + ")."); _watcherCoroutine = ((MonoBehaviour)CustomMainMenuPlugin.Instance).StartCoroutine(WaitForConnectedWorldLoadAndReplaceCoroutine(trigger)); } private static void LogLoading(string message) { CustomMainMenuPlugin.LogInfo(message); } internal static IEnumerator WaitForConnectedWorldLoadAndReplaceCoroutine(string trigger) { if (WatcherRunning) { yield break; } WatcherRunning = true; try { yield return (object)new WaitForSecondsRealtime(0f); float deadlineSearch = Time.realtimeSinceStartup + 2400f; string chosenLoadingArtPath = null; int scanCount = 0; while (Time.realtimeSinceStartup < deadlineSearch && !CustomMainMenuPlugin.TryGetLocalPlayerPresentPlain()) { if (CustomMainMenuPlugin.MainMenuActive) { yield return (object)new WaitForSecondsRealtime(0.5f); continue; } if (chosenLoadingArtPath == null) { chosenLoadingArtPath = CustomMainMenuPlugin.GetRandomLoadingArtPath(); } string text = chosenLoadingArtPath; if (string.IsNullOrEmpty(text) || !File.Exists(text)) { yield return (object)new WaitForSecondsRealtime(0.5f); continue; } Sprite val = SpriteFromFile(text); if ((Object)(object)val != (Object)null) { scanCount++; Stopwatch stopwatch = Stopwatch.StartNew(); LoadingTargetResult loadingTargetResult = FindBestConnectedWorldLoadingTarget(); stopwatch.Stop(); LogLoading($"Loading UI scan #{scanCount} ({trigger}): {stopwatch.ElapsedMilliseconds} ms, valid={loadingTargetResult.IsValid}, score={loadingTargetResult.Score}."); if (loadingTargetResult.IsValid && ApplyLoadingTargetResult(loadingTargetResult, val)) { LoadingTargetResult result = loadingTargetResult; LoadingArtSessionActive = true; LogLoading("Loading art applied (" + trigger + "): " + loadingTargetResult.ObjectName + " @ " + loadingTargetResult.Path + "."); StartForceKeep(loadingTargetResult, val); StartCleanup(result); yield break; } Object.Destroy((Object)(object)val); } yield return (object)new WaitForSecondsRealtime(0.5f); } if (scanCount == 0) { LogLoading("Loading watcher ended without UI scan (" + trigger + "): player spawned or timed out."); } } finally { WatcherRunning = false; if (_watcherCoroutine != null) { _watcherCoroutine = null; } } } private static void StartCleanup(LoadingTargetResult result) { if (!((Object)(object)CustomMainMenuPlugin.Instance == (Object)null) && result.IsValid) { if (_cleanupCoroutine != null) { ((MonoBehaviour)CustomMainMenuPlugin.Instance).StopCoroutine(_cleanupCoroutine); _cleanupCoroutine = null; } _cleanupCoroutine = ((MonoBehaviour)CustomMainMenuPlugin.Instance).StartCoroutine(WaitUntilWorldThenClear(result)); } } private static IEnumerator WaitUntilWorldThenClear(LoadingTargetResult result) { float deadline = Time.realtimeSinceStartup + 2400f; while (!CustomMainMenuPlugin.TryGetLocalPlayerPresentPlain() && Time.realtimeSinceStartup < deadline) { CustomMainMenuPlugin.IsWorldFullyLoaded(); yield return (object)new WaitForSecondsRealtime(0.5f); } CustomMainMenuPlugin.IsWorldFullyLoaded(); FadeOutAndClearLoadingTarget(result); _cleanupCoroutine = null; } private static void StartForceKeep(LoadingTargetResult result, Sprite sprite) { if (!((Object)(object)CustomMainMenuPlugin.Instance == (Object)null) && result.IsValid && !((Object)(object)sprite == (Object)null)) { if (_forceCoroutine != null) { ((MonoBehaviour)CustomMainMenuPlugin.Instance).StopCoroutine(_forceCoroutine); _forceCoroutine = null; } _forceCoroutine = ((MonoBehaviour)CustomMainMenuPlugin.Instance).StartCoroutine(ForceKeepCoroutine(result, sprite)); } } private static IEnumerator ForceKeepCoroutine(LoadingTargetResult result, Sprite sprite) { float deadline = Time.realtimeSinceStartup + 2400f; while (Time.realtimeSinceStartup < deadline && !CustomMainMenuPlugin.TryGetLocalPlayerPresentPlain() && (Object)(object)CustomMainMenuPlugin.Instance != (Object)null) { ApplyLoadingTargetResult(result, sprite); yield return (object)new WaitForSecondsRealtime(2f); } _forceCoroutine = null; } 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_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(absolutePath); 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)); } catch { return null; } } private static void FadeOutAndClearLoadingTarget(LoadingTargetResult result) { if (!result.IsValid || (Object)(object)CustomMainMenuPlugin.Instance == (Object)null) { ClearLoadingTarget(result); LoadingArtSessionActive = false; return; } if (_cleanupCoroutine != null) { ((MonoBehaviour)CustomMainMenuPlugin.Instance).StopCoroutine(_cleanupCoroutine); _cleanupCoroutine = null; } IEnumerator enumerator = LoadingFadeCoroutine(result); ((MonoBehaviour)CustomMainMenuPlugin.Instance).StartCoroutine(enumerator); } 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); LoadingArtSessionActive = false; } 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_0058: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) if (result.IsValid) { 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 MenuAtmosphere { private enum ApplyMode { None, EnvMan, StartSceneFallback } internal const float DefaultNightTimeFraction = 0.875f; internal const float MaintainIntervalSeconds = 0.25f; 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 static ApplyMode _mode; private static string? _appliedEnvironment; private static bool _fallbackSnapshotTaken; private static bool _fallbackLoggedApply; private static bool _envManNightPinned; private static bool _envManHadDebugTimeOfDay; private static float _envManSavedDebugTime; private static bool _fallbackFog; private static Color _fallbackFogColor; private static float _fallbackFogDensity; private static AmbientMode _fallbackAmbientMode; private static Color _fallbackAmbientLight; private static float _fallbackSunIntensity; private static Color _fallbackSunColor; private static Quaternion _fallbackSunRotation; private static bool _fallbackSunStored; private static Light? _cachedDirectionalLight; private static Quaternion _cachedNightRotation; private static float _cachedNightFraction = 0.875f; private static bool _lightResolveAttempted; internal static bool IsFeatureEnabled() { if (CustomMainMenuPlugin.ModEnabled != null) { return CustomMainMenuPlugin.ModEnabled.Value; } return false; } internal static void ResetForMenuSession() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) _mode = ApplyMode.None; _appliedEnvironment = null; _fallbackSnapshotTaken = false; _fallbackSunStored = false; _fallbackLoggedApply = false; _envManNightPinned = false; _cachedDirectionalLight = null; _lightResolveAttempted = false; _cachedNightFraction = GetNightFraction(); _cachedNightRotation = ComputeNightRotation(_cachedNightFraction, 45f); } internal static bool WantsPeriodicMaintain() { return false; } internal static IEnumerator ApplyWhenReady() { if (!IsFeatureEnabled()) { yield break; } for (int i = 0; i < 180; i++) { if (!CustomMainMenuPlugin.MainMenuActive) { break; } if (TryApplyEnvMan() || (i >= 2 && TryApplyStartSceneFallback(logApply: true))) { yield break; } yield return null; } if (CustomMainMenuPlugin.MainMenuActive && _mode == ApplyMode.None) { LogAtmosphere("Menu atmosphere: timed out waiting for EnvMan; start-scene night fallback was not applied."); } } internal static void Apply() { if (IsFeatureEnabled() && !TryApplyEnvMan()) { TryApplyStartSceneFallback(logApply: true); } } internal static void Clear() { ClearEnvMan(); ClearEnvManNightPin(); ClearStartSceneFallback(); _mode = ApplyMode.None; _appliedEnvironment = null; _fallbackLoggedApply = false; _cachedDirectionalLight = null; _lightResolveAttempted = false; } internal static void MaintainAppliedState() { if (!CustomMainMenuPlugin.MainMenuActive || !IsFeatureEnabled()) { return; } switch (_mode) { case ApplyMode.EnvMan: if (!IsEnvManStillApplied()) { TryApplyEnvMan(); } break; case ApplyMode.StartSceneFallback: EnsureEnvManNightPin(); break; } } private static bool TryApplyEnvMan() { return false; } private static bool TryApplyStartSceneFallback(bool logApply) { if (_mode == ApplyMode.EnvMan) { return true; } if (!EnsureDirectionalLightCached()) { return false; } CaptureFallbackSnapshot(); ApplyStartSceneFallbackValuesOnly(); EnsureEnvManNightPin(); _mode = ApplyMode.StartSceneFallback; _appliedEnvironment = "night-fallback"; if (logApply && !_fallbackLoggedApply) { _fallbackLoggedApply = true; LogAtmosphere($"Menu atmosphere applied via start-scene fallback (night, fog density {0.08f:0.###}, fraction {GetNightFraction():0.###})."); } return true; } private static void ApplyStartSceneFallbackValuesOnly() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) _cachedNightFraction = GetNightFraction(); _cachedNightRotation = ComputeNightRotation(_cachedNightFraction, 45f); RenderSettings.fog = true; RenderSettings.fogColor = FallbackFogColor; RenderSettings.fogDensity = 0.08f; RenderSettings.ambientMode = (AmbientMode)3; RenderSettings.ambientLight = FallbackAmbientLight; if ((Object)(object)_cachedDirectionalLight != (Object)null) { ((Component)_cachedDirectionalLight).transform.rotation = _cachedNightRotation; _cachedDirectionalLight.intensity = 0.05f; _cachedDirectionalLight.color = FallbackSunColor; } } private static bool EnsureDirectionalLightCached() { if ((Object)(object)_cachedDirectionalLight != (Object)null) { return true; } if (_lightResolveAttempted) { return false; } _lightResolveAttempted = true; _cachedDirectionalLight = ResolveMenuDirectionalLightOnce(); return (Object)(object)_cachedDirectionalLight != (Object)null; } private static Light? ResolveMenuDirectionalLightOnce() { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Invalid comparison between Unknown and I4 //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Invalid comparison between Unknown and I4 //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Invalid comparison between Unknown and I4 GameObject val = GameObject.Find("Directional light"); if ((Object)(object)val == (Object)null) { val = GameObject.Find("Directional Light"); } if ((Object)(object)val != (Object)null) { Light component = val.GetComponent<Light>(); if ((Object)(object)component != (Object)null && (int)component.type == 1) { return component; } } Light sun = RenderSettings.sun; if ((Object)(object)sun != (Object)null && (int)sun.type == 1) { return sun; } Light[] array = Object.FindObjectsByType<Light>((FindObjectsInactive)1, (FindObjectsSortMode)0); foreach (Light val2 in array) { if ((Object)(object)val2 != (Object)null && (int)val2.type == 1) { return val2; } } return null; } private static Quaternion ComputeNightRotation(float dayFraction, float sunAngle) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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_0046: 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) return Quaternion.Euler(-90f + sunAngle, 0f, 0f) * Quaternion.Euler(0f, -90f, 0f) * Quaternion.Euler(-90f + 360f * dayFraction, 0f, 0f); } private static void CaptureFallbackSnapshot() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0026: 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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) if (!_fallbackSnapshotTaken) { _fallbackFog = RenderSettings.fog; _fallbackFogColor = RenderSettings.fogColor; _fallbackFogDensity = RenderSettings.fogDensity; _fallbackAmbientMode = RenderSettings.ambientMode; _fallbackAmbientLight = RenderSettings.ambientLight; Light cachedDirectionalLight = _cachedDirectionalLight; if ((Object)(object)cachedDirectionalLight != (Object)null) { _fallbackSunStored = true; _fallbackSunIntensity = cachedDirectionalLight.intensity; _fallbackSunColor = cachedDirectionalLight.color; _fallbackSunRotation = ((Component)cachedDirectionalLight).transform.rotation; } else { _fallbackSunStored = false; } _fallbackSnapshotTaken = true; } } private static void ClearEnvMan() { if (_mode == ApplyMode.EnvMan) { EnvMan val = ResolveEnvMan(); if ((Object)(object)val != (Object)null) { val.SetForceEnvironment(string.Empty); val.m_debugTimeOfDay = false; } LogAtmosphere("Menu atmosphere cleared (EnvMan)."); } } private static void EnsureEnvManNightPin() { EnvMan val = ResolveEnvMan(); if (!((Object)(object)val == (Object)null)) { if (!_envManNightPinned) { _envManHadDebugTimeOfDay = val.m_debugTimeOfDay; _envManSavedDebugTime = val.m_debugTime; _envManNightPinned = true; } val.m_debugTimeOfDay = true; val.m_debugTime = GetNightFraction(); } } private static void ClearEnvManNightPin() { if (_envManNightPinned) { EnvMan val = ResolveEnvMan(); if ((Object)(object)val != (Object)null) { val.m_debugTimeOfDay = _envManHadDebugTimeOfDay; val.m_debugTime = _envManSavedDebugTime; } _envManNightPinned = false; } } private static void ClearStartSceneFallback(bool restoreSnapshot = true) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) if (_mode != ApplyMode.StartSceneFallback && !_fallbackSnapshotTaken) { return; } if (restoreSnapshot && _fallbackSnapshotTaken) { RenderSettings.fog = _fallbackFog; RenderSettings.fogColor = _fallbackFogColor; RenderSettings.fogDensity = _fallbackFogDensity; RenderSettings.ambientMode = _fallbackAmbientMode; RenderSettings.ambientLight = _fallbackAmbientLight; if (_fallbackSunStored && (Object)(object)_cachedDirectionalLight != (Object)null) { _cachedDirectionalLight.intensity = _fallbackSunIntensity; _cachedDirectionalLight.color = _fallbackSunColor; ((Component)_cachedDirectionalLight).transform.rotation = _fallbackSunRotation; } } _fallbackSnapshotTaken = false; _fallbackSunStored = false; if (_mode == ApplyMode.StartSceneFallback) { LogAtmosphere("Menu atmosphere cleared (start-scene fallback)."); } } private static bool IsEnvManStillApplied() { EnvMan val = ResolveEnvMan(); if ((Object)(object)val == (Object)null || _mode != ApplyMode.EnvMan) { return false; } if (!val.m_debugTimeOfDay) { return false; } string text = _appliedEnvironment ?? string.Empty; EnvSetup currentEnvironment = val.GetCurrentEnvironment(); if (currentEnvironment != null) { return currentEnvironment.m_name == text; } return false; } private static EnvMan? ResolveEnvMan() { if ((Object)(object)EnvMan.instance != (Object)null) { return EnvMan.instance; } return Object.FindFirstObjectByType<EnvMan>(); } private static float GetNightFraction() { return 0.875f; } private static void LogAtmosphere(string message) { ManualLogSource? modLog = CustomMainMenuPlugin.ModLog; if (modLog != null) { modLog.LogInfo((object)message); } } } internal static class MenuScenery { internal static readonly Vector3 CoastalCharacterPosition = new Vector3(-206.2f, 39.5f, 162.3f); internal static readonly Vector3 CoastalCharacterRotation = new Vector3(19.6f, -211f, 0f); internal static readonly Vector3 CoastalCreditsPosition = new Vector3(-205.3f, 34.5f, 132.1f); internal static readonly Vector3 CoastalCreditsRotation = new Vector3(19.6f, -211f, 0f); internal static readonly Vector3 CoastalStartMainPosition = new Vector3(-208.54f, 32.35f, 131.45f); internal static readonly Vector3 CoastalStartMainRotation = new Vector3(0.72f, -211f, 0f); internal static readonly Vector3 CoastalGamePosition = new Vector3(-204.55f, 38.1f, 158.9f); internal static readonly Vector3 CoastalGameRotation = new Vector3(-181.447f, -48.532f, -180f); internal static readonly Vector3 CoastalSavesPosition = new Vector3(-208.45f, 45.9f, 131.3f); internal static readonly Vector3 CoastalSavesRotation = new Vector3(0.72f, -211f, 0f); internal static readonly Vector3 CoastalPlayerPosition = new Vector3(-204.51f, 36.55f, 157.6f); internal static readonly Vector3 CoastalFirePosition = new Vector3(-203.51f, 36.55f, 158.63f); private const float FireLevelRadius = 4f; private const float FireSmoothRadius = 8f; private const float FireSmoothPower = 2f; private const float FirePaintRadius = 3f; private const PaintType FirePaintType = (PaintType)2; private const float StagingSettleDelaySeconds = 0.5f; private const float FireRetryIntervalSeconds = 0.25f; private const int FireRetryMaxAttempts = 24; private static ConfigEntry<bool>? _enabled; private static ConfigEntry<bool>? _depthOfFieldOnCharacterSelect; private static bool _vanillaSnapshotTaken; private static Vector3 _vanillaCharacterPosition; private static Vector3 _vanillaCreditsPosition; private static Vector3 _vanillaGamePosition; private static Vector3 _vanillaMainPosition; private static Vector3 _vanillaStartPosition; private static Vector3 _vanillaSavesPosition; private static Vector3 _vanillaCharacterRotation; private static Vector3 _vanillaCreditsRotation; private static Vector3 _vanillaGameRotation; private static Vector3 _vanillaMainRotation; private static Vector3 _vanillaStartRotation; private static Vector3 _vanillaSavesRotation; private static Vector3 _vanillaPlayerPosition; private static Vector3 _vanillaPlayerRotation; private static GameObject? _clonedFire; private static GameObject? _sourceMenuFire; private static FejdStartup? _stagingHost; private static Coroutine? _stagingCoroutine; private static bool _propsActivated; private static Behaviour? _cachedDepthOfField; private static FieldInfo? _playerInstanceField; internal static void BindConfig(ConfigFile config) { _enabled = config.Bind<bool>("Menu Scenery", "Enabled", true, "Coastal login viewpoint on start.unity (camera markers, ships/rocks, campfire). Cleared when joining a world."); _depthOfFieldOnCharacterSelect = config.Bind<bool>("Menu Scenery", "DepthOfFieldOnCharacterSelect", true, "Enable depth-of-field on the main camera during character select and credits."); } internal static bool IsFeatureEnabled() { if (CustomMainMenuPlugin.ModEnabled != null && CustomMainMenuPlugin.ModEnabled.Value && _enabled != null) { return _enabled.Value; } return false; } internal static void ResetForMenuSession() { StopStagingCoroutine(); DestroyAllMenuFireClones(destroyImmediate: false); _propsActivated = false; _cachedDepthOfField = null; _sourceMenuFire = null; } internal static void OnSetupGui(FejdStartup startup) { if (IsFeatureEnabled() && !((Object)(object)startup == (Object)null)) { TakeVanillaSnapshotIfNeeded(startup); ApplyStagingImmediate(startup); } } internal static void ScheduleApplyStaging(FejdStartup startup) { if (IsFeatureEnabled() && !((Object)(object)startup == (Object)null)) { StopStagingCoroutine(); _stagingHost = startup; _stagingCoroutine = ((MonoBehaviour)startup).StartCoroutine(ApplyStagingWhenReady(startup)); } } internal static void OnUpdateCamera(FejdStartup startup) { if (IsFeatureEnabled() && CustomMainMenuPlugin.MainMenuActive && !((Object)(object)startup == (Object)null)) { ApplyCameraMarkers(startup); UpdateDepthOfField(startup); } } internal static void OnShowCharacterSelection(FejdStartup startup) { //IL_0026: 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_002e: 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_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) if (IsFeatureEnabled() && CustomMainMenuPlugin.MainMenuActive && !((Object)(object)startup == (Object)null)) { ApplyPlayerPreview(startup); Quaternion rotation = startup.m_cameraMarkerCharacter.rotation; float num = ((Quaternion)(ref rotation)).eulerAngles.y - 180f; Quaternion rotation2 = Quaternion.Euler(0f, num, 0f); startup.m_characterPreviewPoint.rotation = rotation2; GameObject playerInstance = GetPlayerInstance(startup); if ((Object)(object)playerInstance != (Object)null) { playerInstance.transform.rotation = rotation2; } } } internal static void OnCharacterStartPreview(FejdStartup startup) { //IL_0026: 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_002e: 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_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) if (IsFeatureEnabled() && CustomMainMenuPlugin.MainMenuActive && !((Object)(object)startup == (Object)null)) { ApplyPlayerPreview(startup); Quaternion rotation = startup.m_cameraMarkerCharacter.rotation; float num = ((Quaternion)(ref rotation)).eulerAngles.y - 40f; Quaternion rotation2 = Quaternion.Euler(0f, num, 0f); startup.m_characterPreviewPoint.rotation = rotation2; GameObject playerInstance = GetPlayerInstance(startup); if ((Object)(object)playerInstance != (Object)null) { playerInstance.transform.rotation = rotation2; } } } internal static void Clear() { StopStagingCoroutine(); FejdStartup instance = FejdStartup.instance; if (_vanillaSnapshotTaken && (Object)(object)instance != (Object)null) { RestoreVanillaMarkers(instance); RestoreVanillaPlayerPreview(instance); } DestroyAllMenuFireClones(destroyImmediate: true); _propsActivated = false; _cachedDepthOfField = null; _sourceMenuFire = null; } private static IEnumerator ApplyStagingWhenReady(FejdStartup startup) { try { TakeVanillaSnapshotIfNeeded(startup); EnsurePropsVisible(); ApplyCameraMarkers(startup); ApplyPlayerPreview(startup); yield return (object)new WaitForSecondsRealtime(0.5f); int attempt = 0; while (true) { if (attempt < 24 && CustomMainMenuPlugin.MainMenuActive) { if (!EnsureClonedFire()) { yield return (object)new WaitForSecondsRealtime(0.25f); attempt++; continue; } break; } if (CustomMainMenuPlugin.MainMenuActive) { CustomMainMenuPlugin.LogWarn("Menu scenery: MenuFire not found after retries (logout staging)."); } break; } } finally { if (_stagingCoroutine != null && (Object)(object)_stagingHost == (Object)(object)startup) { _stagingCoroutine = null; _stagingHost = null; } } } private static void ApplyStagingImmediate(FejdStartup startup) { EnsurePropsVisible(); ApplyCameraMarkers(startup); ApplyPlayerPreview(startup); EnsureClonedFire(); } private static void TakeVanillaSnapshotIfNeeded(FejdStartup startup) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005e: 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_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_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_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) if (!_vanillaSnapshotTaken) { _vanillaCharacterPosition = startup.m_cameraMarkerCharacter.position; _vanillaCreditsPosition = startup.m_cameraMarkerCredits.position; _vanillaGamePosition = startup.m_cameraMarkerGame.position; _vanillaMainPosition = startup.m_cameraMarkerMain.position; _vanillaStartPosition = startup.m_cameraMarkerStart.position; _vanillaSavesPosition = startup.m_cameraMarkerSaves.position; Quaternion rotation = startup.m_cameraMarkerCharacter.rotation; _vanillaCharacterRotation = ((Quaternion)(ref rotation)).eulerAngles; rotation = startup.m_cameraMarkerCredits.rotation; _vanillaCreditsRotation = ((Quaternion)(ref rotation)).eulerAngles; rotation = startup.m_cameraMarkerGame.rotation; _vanillaGameRotation = ((Quaternion)(ref rotation)).eulerAngles; rotation = startup.m_cameraMarkerMain.rotation; _vanillaMainRotation = ((Quaternion)(ref rotation)).eulerAngles; rotation = startup.m_cameraMarkerStart.rotation; _vanillaStartRotation = ((Quaternion)(ref rotation)).eulerAngles; rotation = startup.m_cameraMarkerSaves.rotation; _vanillaSavesRotation = ((Quaternion)(ref rotation)).eulerAngles; _vanillaPlayerPosition = startup.m_characterPreviewPoint.position; rotation = startup.m_characterPreviewPoint.rotation; _vanillaPlayerRotation = ((Quaternion)(ref rotation)).eulerAngles; _vanillaSnapshotTaken = true; } } private static void EnsurePropsVisible() { if (_propsActivated) { return; } try { GameObject val = GameObject.Find("Static"); if ((Object)(object)val == (Object)null) { CustomMainMenuPlugin.LogWarn("Menu scenery: Static root not found."); return; } Transform val2 = FindChildTransform(val.transform, "props"); if ((Object)(object)val2 == (Object)null) { CustomMainMenuPlugin.LogWarn("Menu scenery: props not found under Static."); return; } ((Component)val2).gameObject.SetActive(true); Transform val3 = FindChildTransform(val2, "Rocks"); if ((Object)(object)val3 != (Object)null) { ((Component)val3).gameObject.SetActive(true); } Transform val4 = FindChildTransform(val2, "ships"); if ((Object)(object)val4 != (Object)null) { ((Component)val4).gameObject.SetActive(true); } _propsActivated = true; } catch (Exception ex) { CustomMainMenuPlugin.LogWarn("Menu scenery: failed to enable props: " + ex.Message); } } private static GameObject? ResolveSourceMenuFire() { if ((Object)(object)_sourceMenuFire != (Object)null) { return _sourceMenuFire; } GameObject[] array = Resources.FindObjectsOfTypeAll<GameObject>(); foreach (GameObject val in array) { if ((Object)(object)val != (Object)null && ((Object)val).name == "MenuFire") { _sourceMenuFire = val; return val; } } return null; } private static bool EnsureClonedFire() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0046: 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_009c: Unknown result type (might be due to invalid IL or missing references) if (!CustomMainMenuPlugin.MainMenuActive) { return false; } if ((Object)(object)_clonedFire != (Object)null) { _clonedFire.transform.position = CoastalFirePosition; return true; } try { GameObject val = ResolveSourceMenuFire(); if ((Object)(object)val == (Object)null) { return false; } _clonedFire = Object.Instantiate<GameObject>(val, CoastalFirePosition, Quaternion.identity); TerrainModifier obj = _clonedFire.AddComponent<TerrainModifier>(); obj.m_level = true; obj.m_levelRadius = 4f; obj.m_smooth = true; obj.m_smoothRadius = 8f; obj.m_smoothPower = 2f; obj.m_paintCleared = true; obj.m_paintType = (PaintType)2; obj.m_paintRadius = 3f; return true; } catch (Exception ex) { CustomMainMenuPlugin.LogWarn("Menu scenery: failed to clone MenuFire: " + ex.Message); return false; } } private static void StopStagingCoroutine() { if ((Object)(object)_stagingHost != (Object)null && _stagingCoroutine != null) { try { ((MonoBehaviour)_stagingHost).StopCoroutine(_stagingCoroutine); } catch (Exception ex) { CustomMainMenuPlugin.LogWarn("Menu scenery: could not stop staging coroutine: " + ex.Message); } } _stagingCoroutine = null; _stagingHost = null; } private static void DestroyAllMenuFireClones(bool destroyImmediate) { if ((Object)(object)_clonedFire != (Object)null) { DestroyFireObject(_clonedFire, destroyImmediate); _clonedFire = null; } GameObject[] array = Resources.FindObjectsOfTypeAll<GameObject>(); foreach (GameObject val in array) { if (!((Object)(object)val == (Object)null) && !(((Object)val).name != "MenuFire(Clone)") && IsCoastalMenuFireClone(val)) { DestroyFireObject(val, destroyImmediate); } } } private static bool IsCoastalMenuFireClone(GameObject go) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) return Vector3.SqrMagnitude(go.transform.position - CoastalFirePosition) < 4f; } private static void DestroyFireObject(GameObject go, bool destroyImmediate) { if (!((Object)(object)go == (Object)null)) { if (destroyImmediate) { Object.DestroyImmediate((Object)(object)go); } else { Object.Destroy((Object)(object)go); } } } private static void ApplyCameraMarkers(FejdStartup startup) { //IL_0006: 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_0026: 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_0046: 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_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: 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_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) startup.m_cameraMarkerCharacter.position = CoastalCharacterPosition; startup.m_cameraMarkerCredits.position = CoastalCreditsPosition; startup.m_cameraMarkerGame.position = CoastalGamePosition; startup.m_cameraMarkerMain.position = CoastalStartMainPosition; startup.m_cameraMarkerStart.position = CoastalStartMainPosition; startup.m_cameraMarkerSaves.position = CoastalSavesPosition; startup.m_cameraMarkerCharacter.rotation = Quaternion.Euler(CoastalCharacterRotation); startup.m_cameraMarkerCredits.rotation = Quaternion.Euler(CoastalCreditsRotation); startup.m_cameraMarkerGame.rotation = Quaternion.Euler(CoastalGameRotation); startup.m_cameraMarkerMain.rotation = Quaternion.Euler(CoastalStartMainRotation); startup.m_cameraMarkerStart.rotation = Quaternion.Euler(CoastalStartMainRotation); startup.m_cameraMarkerSaves.rotation = Quaternion.Euler(CoastalSavesRotation); } private static void ApplyPlayerPreview(FejdStartup startup) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) startup.m_characterPreviewPoint.position = CoastalPlayerPosition; GameObject playerInstance = GetPlayerInstance(startup); if ((Object)(object)playerInstance != (Object)null) { playerInstance.transform.position = CoastalPlayerPosition; } } private static void RestoreVanillaMarkers(FejdStartup startup) { //IL_0006: 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_0026: 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_0046: 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_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL