Decompiled source of ServerQuickConnect v1.0.4

plugins/ServerQuickConnect.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
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.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("Server Quick Connect")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Radamanto")]
[assembly: AssemblyProduct("Server Quick Connect")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("C2C7B9C4-6E5A-4A3D-9F57-5E2B4E8D91A1")]
[assembly: AssemblyFileVersion("1.0.4")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.4.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 ServerQuickConnect
{
	internal static class QuickConnectConnection
	{
		[HarmonyPatch(typeof(FejdStartup), "JoinServer")]
		private static class FejdStartup_JoinServer_CheckNativeJoin
		{
			private static void Postfix(FejdStartup __instance)
			{
				CheckNativeJoin(__instance);
			}

			private static Exception? Finalizer(Exception? __exception)
			{
				if (__exception != null)
				{
					Finish("Native join threw an exception");
				}
				return __exception;
			}
		}

		[HarmonyPatch(typeof(ZNet), "RPC_ClientHandshake")]
		private static class ZNet_RPC_ClientHandshake_RestorePassword
		{
			private static void Postfix()
			{
				RestorePassword();
			}
		}

		[HarmonyPatch(typeof(FejdStartup), "OnSelelectCharacterBack")]
		private static class FejdStartup_OnSelelectCharacterBack_Finish
		{
			private static void Postfix()
			{
				Finish("Character selection cancelled");
			}
		}

		[HarmonyPatch(typeof(FejdStartup), "ShowConnectError")]
		private static class FejdStartup_ShowConnectError_Finish
		{
			private static void Postfix()
			{
				Finish("Native connection error");
			}
		}

		[HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")]
		private static class ZNet_RPC_PeerInfo_FinishConnected
		{
			private static void Postfix()
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Invalid comparison between Unknown and I4
				if ((int)ZNet.GetConnectionStatus() == 2)
				{
					Finish("Connected");
				}
			}
		}

		[HarmonyPatch(typeof(ZNet), "RPC_Error")]
		private static class ZNet_RPC_Error_Finish
		{
			private static void Postfix()
			{
				Finish("Network rejected the connection");
			}
		}

		[HarmonyPatch(typeof(ZNet), "Disconnect")]
		private static class ZNet_Disconnect_Finish
		{
			private static void Prefix(ZNetPeer peer)
			{
				if (peer.m_server)
				{
					Finish("Disconnected from server");
				}
			}
		}

		[HarmonyPatch(typeof(ZNet), "Shutdown")]
		private static class ZNet_Shutdown_Finish
		{
			private static void Prefix()
			{
				Finish("Network shutdown");
			}
		}

		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static PopupButtonCallback <>9__16_0;

			internal void <ShowError>b__16_0()
			{
				UnifiedPopup.Pop();
			}
		}

		private static bool _passwordOverridden;

		private static string? _savedPassword;

		private static string? _password;

		private static ServerJoinData _server;

		internal static bool Busy { get; private set; }

		private static void Join(ServerJoinData server)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			_server = server;
			try
			{
				_savedPassword = FejdStartup.ServerPassword;
				_passwordOverridden = true;
				FejdStartup.ServerPassword = (string.IsNullOrEmpty(_password) ? null : _password);
				ServerQuickConnectPlugin.Log.LogInfo((object)"Quick connect: server available; opening native join.");
				FejdStartup instance = FejdStartup.m_instance;
				instance.ProceedJoinRequest(server);
				if (instance.m_queuedJoinServer != server && instance.m_joinServer != server)
				{
					Finish("Join request rejected by the game");
				}
			}
			catch (Exception error)
			{
				Fail("error", error);
			}
		}

		internal static void CheckNativeJoin(FejdStartup startup)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (Busy && !(startup.m_joinServer != _server))
			{
				if (!((MonoBehaviour)startup).IsInvoking("LoadMainSceneIfBackendSelected") && !ZNet.HasServerHost())
				{
					Finish("Native join did not start");
				}
				else
				{
					ServerQuickConnectPlugin.Log.LogInfo((object)"Quick connect: native connection started.");
				}
			}
		}

		internal static void RestorePassword()
		{
			if (_passwordOverridden)
			{
				if (FejdStartup.ServerPassword == (string.IsNullOrEmpty(_password) ? null : _password))
				{
					FejdStartup.ServerPassword = _savedPassword;
				}
				_savedPassword = (_password = null);
				_passwordOverridden = false;
			}
		}

		internal static void Start()
		{
			//IL_00e1: 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)
			if (Busy || !ServerQuickConnectPlugin.CE_QuickConnect_Enabled.Value || !Object.op_Implicit((Object)(object)FejdStartup.m_instance))
			{
				return;
			}
			string text = ServerQuickConnectPlugin.CE_QuickConnect_IP.Value?.Trim() ?? "";
			int value = ServerQuickConnectPlugin.CE_QuickConnect_Port.Value;
			if (string.IsNullOrWhiteSpace(text) || value < 1 || value > 65535)
			{
				ShowError("invalid");
				return;
			}
			try
			{
				_password = ServerQuickConnectPlugin.CE_QuickConnect_Password.Value;
				Busy = true;
				QuickConnectMenu.Refresh();
				ServerQuickConnectPlugin.Log.LogInfo((object)("Quick connect: joining " + text + ":" + value + "."));
				Join(new ServerJoinData(new ServerJoinDataDedicated(text, (ushort)value)));
			}
			catch (Exception error)
			{
				Fail("error", error);
			}
		}

		internal static void Finish(string reason)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			if (Busy)
			{
				ServerQuickConnectPlugin.Log.LogInfo((object)("Quick connect: " + reason + "."));
			}
			Busy = false;
			RestorePassword();
			_password = null;
			_server = ServerJoinData.None;
			QuickConnectMenu.Refresh();
		}

		private static void Fail(string reason, Exception? error = null)
		{
			if (error != null)
			{
				ServerQuickConnectPlugin.Log.LogWarning((object)("Quick connect failed: " + error.GetType().Name));
			}
			Finish(reason);
			ShowError(reason);
		}

		private static void ShowError(string reason)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Expected O, but got Unknown
			//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)
			//IL_002a: Expected O, but got Unknown
			string text = QuickConnectText.Get(reason);
			object obj = <>c.<>9__16_0;
			if (obj == null)
			{
				PopupButtonCallback val = delegate
				{
					UnifiedPopup.Pop();
				};
				<>c.<>9__16_0 = val;
				obj = (object)val;
			}
			UnifiedPopup.Push((PopupBase)new WarningPopup("$error_failedconnect", text, (PopupButtonCallback)obj, true));
		}
	}
	internal static class QuickConnectText
	{
		private static readonly Dictionary<string, string> English = new Dictionary<string, string>
		{
			["invalid"] = "Check the configured server address and port.",
			["error"] = "Could not start the connection. Check the log."
		};

		private static readonly Dictionary<string, string> PortugueseBrazilian = new Dictionary<string, string>
		{
			["invalid"] = "Verifique o endereço e a porta do servidor na configuração.",
			["error"] = "Não foi possível iniciar a conexão. Consulte o log."
		};

		internal static string Get(string key)
		{
			Dictionary<string, string> dictionary = ((Localization.instance != null && Localization.instance.GetSelectedLanguage() == "Portuguese_Brazilian") ? PortugueseBrazilian : English);
			string value;
			return dictionary.TryGetValue(key, out value) ? value : key;
		}
	}
	internal static class QuickConnectMenu
	{
		[HarmonyPatch(typeof(FejdStartup), "SetupGui")]
		private static class FejdStartup_SetupGui_AddButton
		{
			private static void Postfix(FejdStartup __instance)
			{
				QuickConnectConnection.Finish("Main menu initialized");
				if (ServerQuickConnectPlugin.CE_QuickConnect_Enabled.Value)
				{
					ApplyButton(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(FejdStartup), "OnLanguageChange")]
		private static class FejdStartup_OnLanguageChange_RefreshButton
		{
			private static void Postfix()
			{
				Refresh();
			}
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static UnityAction <0>__Start;
		}

		private static GameObject? _quickConnectButton;

		private static string ButtonText => ServerQuickConnectPlugin.CE_QuickConnect_ButtonText.Value;

		internal static void Refresh()
		{
			if (Object.op_Implicit((Object)(object)_quickConnectButton))
			{
				_quickConnectButton.SetActive(ServerQuickConnectPlugin.CE_QuickConnect_Enabled.Value);
				SetButtonText(_quickConnectButton, ButtonText);
				Button val = FindButton(_quickConnectButton);
				if (Object.op_Implicit((Object)(object)val))
				{
					((Selectable)val).interactable = !QuickConnectConnection.Busy;
				}
			}
		}

		private static Button? FindButton(GameObject go)
		{
			Button component = go.GetComponent<Button>();
			return Object.op_Implicit((Object)(object)component) ? component : go.GetComponentInChildren<Button>(true);
		}

		internal static void ApplyButton(FejdStartup fs)
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected O, but got Unknown
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0170: Expected O, but got Unknown
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bb: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)fs) || !Object.op_Implicit((Object)(object)fs.m_menuList))
			{
				return;
			}
			if (Object.op_Implicit((Object)(object)_quickConnectButton))
			{
				SetButtonText(_quickConnectButton, ButtonText);
				Button val = FindButton(_quickConnectButton);
				if (Object.op_Implicit((Object)(object)val))
				{
					val.onClick = new ButtonClickedEvent();
					ButtonClickedEvent onClick = val.onClick;
					object obj = <>O.<0>__Start;
					if (obj == null)
					{
						UnityAction val2 = QuickConnectConnection.Start;
						<>O.<0>__Start = val2;
						obj = (object)val2;
					}
					((UnityEvent)onClick).AddListener((UnityAction)obj);
					((Selectable)val).interactable = !QuickConnectConnection.Busy;
				}
				_quickConnectButton.transform.SetSiblingIndex(0);
				return;
			}
			Transform val3 = fs.m_menuList.transform.Find("MenuEntries/Start game");
			if (!Object.op_Implicit((Object)(object)val3))
			{
				return;
			}
			Button component = ((Component)val3).GetComponent<Button>();
			if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)((Component)component).transform.parent))
			{
				return;
			}
			GameObject val4 = Object.Instantiate<GameObject>(((Component)component).gameObject, ((Component)component).transform.parent, false);
			((Object)val4).name = "RD_QuickConnectButton";
			val4.SetActive(true);
			Button val5 = FindButton(val4);
			if (!Object.op_Implicit((Object)(object)val5))
			{
				Object.Destroy((Object)(object)val4);
				return;
			}
			val5.onClick = new ButtonClickedEvent();
			((Selectable)val5).navigation = ((Selectable)component).navigation;
			((Selectable)val5).transition = ((Selectable)component).transition;
			((Selectable)val5).interactable = !QuickConnectConnection.Busy;
			ButtonClickedEvent onClick2 = val5.onClick;
			object obj2 = <>O.<0>__Start;
			if (obj2 == null)
			{
				UnityAction val6 = QuickConnectConnection.Start;
				<>O.<0>__Start = val6;
				obj2 = (object)val6;
			}
			((UnityEvent)onClick2).AddListener((UnityAction)obj2);
			SetButtonText(val4, ButtonText);
			val4.transform.SetSiblingIndex(0);
			_quickConnectButton = val4;
		}

		private static void SetButtonText(GameObject go, string text)
		{
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			Transform val = go.transform.Find("Text");
			if (!Object.op_Implicit((Object)(object)val))
			{
				return;
			}
			Color color;
			bool flag = TryGetButtonColor(out color);
			Text component = ((Component)val).GetComponent<Text>();
			if (Object.op_Implicit((Object)(object)component))
			{
				component.text = text;
				if (flag)
				{
					((Graphic)component).color = color;
				}
			}
			TMP_Text component2 = ((Component)val).GetComponent<TMP_Text>();
			if (Object.op_Implicit((Object)(object)component2))
			{
				component2.text = text;
				if (flag)
				{
					((Graphic)component2).color = color;
					component2.faceColor = Color32.op_Implicit(color);
					component2.enableVertexGradient = false;
				}
				component2.ForceMeshUpdate(true, true);
			}
		}

		private static bool TryGetButtonColor(out Color color)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			color = default(Color);
			string text = ServerQuickConnectPlugin.CE_QuickConnect_ButtonColor.Value?.Trim() ?? "";
			if (string.IsNullOrEmpty(text))
			{
				return false;
			}
			return ColorUtility.TryParseHtmlString(text, ref color);
		}
	}
	[BepInPlugin("radamanto.ServerQuickConnect", "Server Quick Connect", "1.0.4")]
	public class ServerQuickConnectPlugin : BaseUnityPlugin
	{
		internal static ConfigEntry<bool> CE_QuickConnect_Enabled;

		internal static ConfigEntry<string> CE_QuickConnect_ButtonText;

		internal static ConfigEntry<string> CE_QuickConnect_IP;

		internal static ConfigEntry<int> CE_QuickConnect_Port;

		internal static ConfigEntry<string> CE_QuickConnect_Password;

		internal static ConfigEntry<string> CE_QuickConnect_ButtonColor;

		public const string ModGUID = "radamanto.ServerQuickConnect";

		public const string ModName = "Server Quick Connect";

		public const string ModVersion = "1.0.4";

		internal static ServerQuickConnectPlugin Instance;

		private readonly Harmony _harmony = new Harmony("radamanto.ServerQuickConnect");

		internal static ManualLogSource Log => ((BaseUnityPlugin)Instance).Logger;

		private void BindConfiguration()
		{
			bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet;
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
			try
			{
				CE_QuickConnect_Enabled = Cfg("02 - Quick Connect", "02.01 - Enabled", defaultValue: true, "Adds a main menu button that connects directly to the server.");
				CE_QuickConnect_ButtonText = Cfg("02 - Quick Connect", "02.02 - ButtonText", "Connect Vikings Server", "Text displayed on the main menu button.");
				CE_QuickConnect_ButtonColor = Cfg("02 - Quick Connect", "02.03 - ButtonColor", "#8CFF8CFF", "Button text color in HEX. Example: #8CFF8CFF. If invalid, the default template color is kept.");
				CE_QuickConnect_IP = Cfg("02 - Quick Connect", "02.04 - IP", "127.0.0.1", "Server IP address or hostname. The connection uses the game's native join flow.");
				CE_QuickConnect_Port = Cfg("02 - Quick Connect", "02.05 - Port", 2456, "Server game port, from 1 to 65535.");
				CE_QuickConnect_Password = Cfg("02 - Quick Connect", "02.06 - Password", "", "Server password. Leave empty to use the game's password prompt.");
			}
			finally
			{
				((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet;
			}
			((BaseUnityPlugin)this).Config.Save();
		}

		private ConfigEntry<T> Cfg<T>(string section, string key, T defaultValue, string description)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			return ((BaseUnityPlugin)this).Config.Bind<T>(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()));
		}

		private void Awake()
		{
			Instance = this;
			BindConfiguration();
			_harmony.PatchAll();
		}

		private void OnDestroy()
		{
			QuickConnectConnection.Finish("Plugin unloaded");
			((MonoBehaviour)this).StopAllCoroutines();
			_harmony.UnpatchSelf();
		}
	}
}