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 QuickServerConnect v1.0.0
BepInEx/plugins/QuickServerConnect.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Dedryx")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright © Dedryx 2026")] [assembly: AssemblyDescription("Double-click a Valheim server to connect and securely remember its password.")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("QuickServerConnect")] [assembly: AssemblyTitle("QuickServerConnect")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [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 QuickServerConnect { [BepInPlugin("dedryx.quickserverconnect", "QuickServerConnect", "1.0.0")] [BepInProcess("valheim.exe")] public sealed class Plugin : BaseUnityPlugin { [HarmonyPatch(typeof(ServerListGui), "OnSelectedServer")] private static class ServerRowClickPatch { private static void Postfix(ServerListGui __instance, ServerJoinData selected) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) if (!modEnabled.Value) { return; } float unscaledTime = Time.unscaledTime; float value = doubleClickInterval.Value; float num = (float.IsNaN(value) ? 0.35f : Mathf.Clamp(value, 0.1f, 1f)); bool num2 = ((ServerJoinData)(ref lastClickedServer)).IsValid && ((ServerJoinData)(ref lastClickedServer)).Equals(selected) && unscaledTime - lastClickTime <= num; lastClickedServer = selected; lastClickTime = unscaledTime; if (!num2 || !((Object)(object)__instance.m_joinGameButton != (Object)null) || !((Selectable)__instance.m_joinGameButton).interactable) { return; } lastClickTime = float.NegativeInfinity; try { FejdStartup val = Startup.Invoke(__instance); if ((Object)(object)val != (Object)null) { val.OnJoinStart(); } } catch (Exception exception) { log.Error("Double-click connect", exception); } } } [HarmonyPatch(typeof(FejdStartup), "JoinServer")] private static class JoinServerPatch { private static void Prefix(FejdStartup __instance) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (modEnabled.Value && __instance.HasServerToJoin()) { try { BeginJoin(__instance.GetServerToJoin()); } catch (Exception exception) { activeServerKey = null; log.Error("Server identity", exception); } } } } [HarmonyPatch(typeof(ZNet), "RPC_ClientHandshake")] private static class PasswordPromptPatch { private static void Postfix(ZNet __instance, bool needPassword) { if (!modEnabled.Value || !needPassword || autoSubmissionAttempted || !autoSubmitSavedPasswords.Value || string.IsNullOrEmpty(activeServerKey)) { return; } autoSubmissionAttempted = true; string text = credentials.Get(activeServerKey); if (string.IsNullOrEmpty(text)) { return; } candidatePassword = text; submittedSavedPassword = true; submittingSavedPassword = true; try { SubmitPassword(__instance, text); } catch (Exception exception) { submittedSavedPassword = false; candidatePassword = null; credentials.Remove(activeServerKey); log.Error("Saved-password submission", exception); } finally { submittingSavedPassword = false; text = null; } } } [HarmonyPatch(typeof(ZNet), "OnPasswordEntered")] private static class PasswordEnteredPatch { private static void Prefix(string pwd) { if (modEnabled.Value && !string.IsNullOrEmpty(pwd)) { candidatePassword = pwd; if (!submittingSavedPassword) { submittedSavedPassword = false; } } } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] private static class ConnectionAcceptedPatch { private static void Postfix() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Invalid comparison between Unknown and I4 if (modEnabled.Value && (int)ZNet.GetConnectionStatus() == 2) { if (rememberPasswords.Value && !string.IsNullOrEmpty(activeServerKey) && !string.IsNullOrEmpty(candidatePassword)) { credentials.Set(activeServerKey, candidatePassword); } candidatePassword = null; submittedSavedPassword = false; } } } [HarmonyPatch(typeof(ZNet), "RPC_Error")] private static class ConnectionErrorPatch { private static void Postfix(int error) { if (modEnabled.Value && error == 6 && submittedSavedPassword && !string.IsNullOrEmpty(activeServerKey)) { credentials.Remove(activeServerKey); candidatePassword = null; submittedSavedPassword = false; } } } private sealed class ManualLogSourceProxy { private readonly ManualLogSource source; internal ManualLogSourceProxy(ManualLogSource source) { this.source = source; } internal void Error(string operation, Exception exception) { source.LogError((object)(operation + " failed (" + exception.GetType().Name + ").")); } } private sealed class CredentialStore { private static readonly byte[] Entropy = Encoding.UTF8.GetBytes("dedryx.quickserverconnect|credentials|v1"); private readonly string path; private readonly ManualLogSourceProxy logger; private readonly Dictionary<string, string> encrypted = new Dictionary<string, string>(StringComparer.Ordinal); internal CredentialStore(string path, ManualLogSourceProxy logger) { this.path = path; this.logger = logger; Load(); } internal static string HashIdentity(string identity) { using SHA256 sHA = SHA256.Create(); return BitConverter.ToString(sHA.ComputeHash(Encoding.UTF8.GetBytes(identity))).Replace("-", ""); } private void Load() { try { if (!File.Exists(path)) { return; } string[] array = File.ReadAllLines(path); foreach (string text in array) { int num = text.IndexOf('\t'); if (num == 64 && num < text.Length - 1) { encrypted[text.Substring(0, num)] = text.Substring(num + 1); } } } catch (Exception exception) { logger.Error("Credential load", exception); } } internal string Get(string key) { if (!encrypted.TryGetValue(key, out var value)) { return null; } try { byte[] array = Convert.FromBase64String(value); byte[] array2 = ProtectedData.Unprotect(array, Entropy, (DataProtectionScope)0); string result = Encoding.UTF8.GetString(array2); Array.Clear(array2, 0, array2.Length); Array.Clear(array, 0, array.Length); return result; } catch (Exception exception) { logger.Error("Credential decrypt", exception); Remove(key); return null; } } internal void Set(string key, string password) { try { byte[] bytes = Encoding.UTF8.GetBytes(password); byte[] array = ProtectedData.Protect(bytes, Entropy, (DataProtectionScope)0); encrypted[key] = Convert.ToBase64String(array); Array.Clear(bytes, 0, bytes.Length); Array.Clear(array, 0, array.Length); Save(); } catch (Exception exception) { logger.Error("Credential save", exception); } } internal void Remove(string key) { if (encrypted.Remove(key)) { Save(); } } internal void Clear() { encrypted.Clear(); try { if (File.Exists(path)) { File.Delete(path); } } catch (Exception exception) { logger.Error("Credential clear", exception); } } private void Save() { try { Directory.CreateDirectory(Path.GetDirectoryName(path)); List<string> list = new List<string>(encrypted.Count); foreach (KeyValuePair<string, string> item in encrypted) { list.Add(item.Key + "\t" + item.Value); } File.WriteAllLines(path, list.ToArray()); } catch (Exception exception) { logger.Error("Credential write", exception); } } } [CompilerGenerated] private static class <>O { public static ConsoleEvent <0>__OnConsoleCommand; } private static ConfigEntry<bool> modEnabled; private static ConfigEntry<float> doubleClickInterval; private static ConfigEntry<bool> autoSubmitSavedPasswords; private static ConfigEntry<bool> rememberPasswords; private static ManualLogSourceProxy log; private static CredentialStore credentials; private static ServerJoinData lastClickedServer = ServerJoinData.None; private static float lastClickTime = float.NegativeInfinity; private static string activeServerKey; private static string candidatePassword; private static bool autoSubmissionAttempted; private static bool submittingSavedPassword; private static bool submittedSavedPassword; private static readonly FieldRef<ServerListGui, FejdStartup> Startup = AccessTools.FieldRefAccess<ServerListGui, FejdStartup>("m_startup"); private static readonly Action<ZNet, string> SubmitPassword = AccessTools.MethodDelegate<Action<ZNet, string>>(AccessTools.DeclaredMethod(typeof(ZNet), "OnPasswordEntered", new Type[1] { typeof(string) }, (Type[])null), (object)null, true); private void Awake() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Expected O, but got Unknown modEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable QuickServerConnect."); doubleClickInterval = ((BaseUnityPlugin)this).Config.Bind<float>("General", "DoubleClickInterval", 0.35f, new ConfigDescription("Maximum seconds between clicks on the same server.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 1f), Array.Empty<object>())); autoSubmitSavedPasswords = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AutoSubmitSavedPasswords", true, "Automatically submit a remembered password."); rememberPasswords = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RememberPasswords", true, "Remember passwords after the server accepts them."); log = new ManualLogSourceProxy(((BaseUnityPlugin)this).Logger); credentials = new CredentialStore(Path.Combine(Paths.ConfigPath, "QuickServerConnect", "credentials.dat"), log); object obj = <>O.<0>__OnConsoleCommand; if (obj == null) { ConsoleEvent val = OnConsoleCommand; <>O.<0>__OnConsoleCommand = val; obj = (object)val; } new ConsoleCommand("quickserverconnect", "quickserverconnect clearpasswords - delete all remembered server passwords", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); new Harmony("dedryx.quickserverconnect").PatchAll(typeof(Plugin).Assembly); } private static void OnConsoleCommand(ConsoleEventArgs args) { if (args.Length == 2 && string.Equals(args[1], "clearpasswords", StringComparison.OrdinalIgnoreCase)) { credentials.Clear(); args.Context.AddString("QuickServerConnect: saved passwords cleared."); } else { args.Context.AddString("Usage: quickserverconnect clearpasswords"); } } private static string GetServerKey(ServerJoinData server) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected I4, but got Unknown //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: 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) //IL_001f: 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) ServerJoinDataType type = server.m_type; string identity; switch (type - 1) { case 2: { ServerJoinDataDedicated dedicated = ((ServerJoinData)(ref server)).Dedicated; identity = "dedicated|" + ((ServerJoinDataDedicated)(ref dedicated)).GetHost().Trim().TrimEnd('/') .ToLowerInvariant() + "|" + dedicated.m_port; break; } case 0: identity = "steam|" + ((ServerJoinData)(ref server)).SteamUser.m_joinUserID.m_SteamID; break; case 1: identity = "playfab|" + ((ServerJoinData)(ref server)).PlayFabUser.m_remotePlayerId; break; default: return null; } return CredentialStore.HashIdentity(identity); } private static void BeginJoin(ServerJoinData server) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) activeServerKey = GetServerKey(server); candidatePassword = null; submittedSavedPassword = false; autoSubmissionAttempted = false; } } }