using System; using System.Collections; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn.Utils; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.Networking; using UnityEngine.UI; using Zen; using Zen.Lib; using Zen.Lib.Config; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("ZenLogin")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ZenLogin")] [assembly: AssemblyCopyright("Copyright \ufffd 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")] [assembly: AssemblyFileVersion("1.4.1")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.4.1.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ZenLogin { internal static class Configs { public static readonly ConfigEntry Enabled; public static readonly ConfigEntry ServerAddress; public static readonly ConfigEntry ServerPassword; public static readonly ConfigEntry ShowMenuLogout; public static readonly ConfigEntry ShowStartupLogos; public static readonly ConfigEntry LogoUrl; public static readonly ConfigEntry ShowChangeLog; public static readonly ConfigEntry ShowModdedText; public static readonly ConfigEntry ShowMerchStore; static Configs() { Enabled = Config.Define(false, "General", "Enabled", true, "When enabled, automatically connect to the dedicated server after character selection.\r\nNOTE: You can temporarily disable this by holding the Alt key before clicking \"Connect\""); ServerAddress = Config.Define(false, "General", "Server Address", string.Empty, "Host or IP address and port of the dedicated server. (Example: 127.0.0.1:2457)"); ServerPassword = Config.Define(false, "General", "Server Password", string.Empty, "If left blank and the server requires a password it will prompt the user for the password."); ShowMenuLogout = Config.Define(true, "General", "Show Logout Menu", true, "Show the menu option \"Logout\" on the pause menu. (Vanilla: true)\r\nIf disabled it will force players to quit the game instead of logout.\r\nThis can be helpful when server admins need to force players to reboot the client."); ShowStartupLogos = Config.Define(false, "General", "Show Startup Logos", true, "Show the startup logo branding. Turn this off to load the game faster.\r\nAlso, they are now always skippable via click or button press regardless of this configs's value."); LogoUrl = Config.Define(false, "Title Screen", "Logo Url", string.Empty, "Set the path to a custom main menu title screen logo.\r\nIt can be a URL or a file path.\r\nIf it is a file path, it must be relative to: BepInEx/config/ \r\nYou can create a subfolder if you wish.\r\nMust be a .png file. Default dimensions: 1000x384\r\nExample: \r\n- YourLogo.png\r\n- your_folder/YourLogo.png\r\n- https://example.com/your_logo.png"); ShowChangeLog = Config.Define(false, "Title Screen", "Show Changelog", true, "Show the Changelog Patch Notes on the title screen. (Vanilla: true)"); ShowModdedText = Config.Define(false, "Title Screen", "Show Modded Text", true, "Show the Modded Text Info on the title screen. (Vanilla: true)"); ShowMerchStore = Config.Define(false, "Title Screen", "Show MerchStore", true, "Show the link to the merch store. (Vanilla: true)"); } } [HarmonyPatch] internal static class Login { private static bool _disableAddToRecentServersList; private static bool IsAltKeyPressed { get { if (!ZInput.GetKey((KeyCode)308, true)) { return ZInput.GetKey((KeyCode)307, true); } return true; } } private static bool IsValid { get { if (Configs.Enabled.Value && !IsAltKeyPressed) { return !Utility.IsNullOrWhiteSpace(Configs.ServerAddress.Value); } return false; } } private static void InitConnection() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) bool flag = !Utility.IsNullOrWhiteSpace(Configs.ServerPassword.Value); bool flag2 = default(bool); InterpolatedString val = new InterpolatedString(38, 2, ref flag2); if (flag2) { val.AppendLiteral("Connecting to server "); val.AppendFormatted(Configs.ServerAddress.Value); val.AppendLiteral(", with password? "); val.AppendFormatted(flag); } Logging.Info(val, 0); FejdStartup.ServerPassword = (flag ? Configs.ServerPassword.Value : null); FejdStartup.instance.m_queuedJoinServer = new ServerJoinData(new ServerJoinDataDedicated(Configs.ServerAddress.Value)); _disableAddToRecentServersList = true; } [HarmonyPrefix] [HarmonyPatch(typeof(FejdStartup), "OnCharacterStart")] private static void FejdStartup_OnCharacterStart(FejdStartup __instance) { if (IsValid) { InitConnection(); } else { Logging.Info("Auto connect disabled", 0); } } [HarmonyPostfix] [HarmonyPatch(typeof(FejdStartup), "Update")] private static void FejdStartup_Update(FejdStartup __instance) { string text = (IsValid ? "$menu_connect" : "$menu_start"); ((Component)((Component)__instance.m_csStartButton).transform.Find("Text")).GetComponent().text = StringExt.Localize(text); } [HarmonyPrefix] [HarmonyPatch(typeof(ServerListGui), "AddToRecentServersList")] private static void ServerListGui_AddToRecentServersList(ref bool __runOriginal) { __runOriginal = !_disableAddToRecentServersList; _disableAddToRecentServersList = false; } } [HarmonyPatch] internal static class Logo { private static Sprite? _logo; private static Sprite? _valheimLogo; public static void LoadFrom(string urlOrFile) { urlOrFile = urlOrFile.Trim(); if (Utility.IsNullOrWhiteSpace(urlOrFile)) { ResetLogo(); } else if (urlOrFile.StartsWith("http")) { LoadFromWeb(urlOrFile); } else { LoadFromFile(urlOrFile); } } private static void LoadFromFile(string filePath) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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) bool flag = default(bool); InterpolatedString val = new InterpolatedString(21, 1, ref flag); if (flag) { val.AppendLiteral("Load logo from file: "); val.AppendFormatted(filePath); } Logging.Info(val, 0); _logo = AssetUtils.LoadSpriteFromFile("../config/" + filePath, Vector2.one * 0.5f); if (!Object.op_Implicit((Object)(object)_logo)) { ResetLogo(); } else { SetLogo(); } } private static void LoadFromWeb(string url) { ((MonoBehaviour)ZenMod.Instance).StartCoroutine(Download(url)); } private static IEnumerator Download(string url) { bool flag = default(bool); InterpolatedString val = new InterpolatedString(27, 1, ref flag); if (flag) { val.AppendLiteral("Downloading logo from url: "); val.AppendFormatted(url); } Logging.Info(val, 0); UnityWebRequest req = UnityWebRequestTexture.GetTexture(url); try { req.timeout = 20; req.redirectLimit = 5; yield return req.SendWebRequest(); if ((int)req.result != 1) { Logging.Warning((object)("Failed to load logo from url '" + url + "': " + req.error), 0); ResetLogo(); yield break; } Texture2D content = DownloadHandlerTexture.GetContent(req); if (!Object.op_Implicit((Object)(object)content)) { Logging.Warning((object)("Invalid texture data from '" + url + "'"), 0); ResetLogo(); yield break; } _logo = Sprite.Create(content, new Rect(0f, 0f, (float)((Texture)content).width, (float)((Texture)content).height), Vector2.one * 0.5f); val = new InterpolatedString(36, 1, ref flag); if (flag) { val.AppendLiteral("Download complete. Logo dimensions: "); Rect rect = _logo.rect; val.AppendFormatted(((Rect)(ref rect)).size); } Logging.Info(val, 0); SetLogo(); } finally { ((IDisposable)req)?.Dispose(); } } public static void SetLogo() { if (Object.op_Implicit((Object)(object)_logo) && Object.op_Implicit((Object)(object)FejdStartup.instance)) { Logging.Info("Set logo", 0); Image component = ((Component)FejdStartup.instance.m_mainMenu.transform.Find("Logo/LOGO")).GetComponent(); if (!Object.op_Implicit((Object)(object)_valheimLogo)) { _valheimLogo = component.sprite; } component.sprite = _logo; } } private static void ResetLogo() { Logging.Info("Reset main menu logo", 0); _logo = _valheimLogo; SetLogo(); } [HarmonyPostfix] [HarmonyPatch(typeof(SceneLoader), "Awake")] private static void SceneLoader_Awake(SceneLoader __instance) { __instance._showLogos = Configs.ShowStartupLogos.Value; __instance._skipEnabled = true; __instance._logosSkippable = true; } } [HarmonyPatch] internal static class MenuPatch { [HarmonyPrefix] [HarmonyPatch(typeof(Menu), "Show")] private static void Menu_Show(Menu __instance) { Transform val = ((Transform)__instance.menuEntriesParent).Find("Logout"); if (Object.op_Implicit((Object)(object)val)) { ((Component)val).gameObject.SetActive(Configs.ShowMenuLogout.Value); } } } [BepInPlugin("ZenDragon.ZenLogin", "ZenLogin", "1.4.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [SynchronizationMode(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] internal class Plugin : ZenMod { public const string PluginName = "ZenLogin"; public const string PluginVersion = "1.4.1"; public const string PluginGUID = "ZenDragon.ZenLogin"; protected override void Setup() { } private void Start() { Logo.LoadFrom(Configs.LogoUrl.Value); } protected override void TitleScene(bool isFirstBoot) { Logo.SetLogo(); } protected override void WorldStart() { } protected override void Shutdown() { } } [HarmonyPatch] internal static class TitleScreen { [HarmonyPostfix] [HarmonyPatch(typeof(FejdStartup), "SetupGui")] private static void FejdStartup_SetupGui() { ApplyConfig(); } static TitleScreen() { Configs.LogoUrl.SettingChanged += delegate { Logo.LoadFrom(Configs.LogoUrl.Value); }; Configs.ShowChangeLog.SettingChanged += delegate { ApplyConfig(); }; Configs.ShowModdedText.SettingChanged += delegate { ApplyConfig(); }; Configs.ShowMerchStore.SettingChanged += delegate { ApplyConfig(); }; } private static void ApplyConfig() { if (Object.op_Implicit((Object)(object)FejdStartup.instance)) { ShowChangeLog(Configs.ShowChangeLog.Value); ShowModdedText(Configs.ShowModdedText.Value); ShowMerchStore(Configs.ShowMerchStore.Value); } } private static void ShowMerchStore(bool isVisible) { Transform val = ((Component)FejdStartup.instance).transform.Find("Menu/TopRight"); if (Object.op_Implicit((Object)(object)val)) { ((Component)val).gameObject.SetActive(isVisible); } } private static void ShowChangeLog(bool isVisible) { ((Component)((Component)FejdStartup.instance.m_patchLogScroll).transform.parent).gameObject.SetActive(isVisible); } private static void ShowModdedText(bool isVisible) { FejdStartup.instance.m_moddedText.SetActive(isVisible); } } }