Decompiled source of Direct Connect v1.0.0

BigWalk.DirectConnect.dll

Decompiled 2 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using BigWalk.DirectConnect.Common;
using BigWalk.DirectConnect.Localization;
using BigWalk.DirectConnect.Networking;
using BigWalk.DirectConnect.Tuning;
using BigWalk.DirectConnect.UI;
using BigWalk.DirectConnect.Warnings;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Reflection;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("BigWalk.DirectConnect")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+17f7138308c4c59ce7dd80d0c69dbc0ae3c2993a")]
[assembly: AssemblyProduct("BigWalk.DirectConnect")]
[assembly: AssemblyTitle("BigWalk.DirectConnect")]
[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 BigWalk.DirectConnect
{
	public sealed class ModController : MonoBehaviour
	{
		private const float TuningInterval = 0.5f;

		private float _nextTuning;

		public ModController(IntPtr pointer)
			: base(pointer)
		{
		}

		private void Update()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			IpJoinSection.Tick();
			AddressResolver.Tick();
			PasswordAutoFill.Tick();
			bool flag = default(bool);
			try
			{
				WarningHider.HandleToggleKey();
			}
			catch (Exception ex)
			{
				ManualLogSource logger = Plugin.Logger;
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(23, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Warning toggle failed: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				logger.LogError(val);
			}
			if (Time.unscaledTime < _nextTuning)
			{
				return;
			}
			_nextTuning = Time.unscaledTime + 0.5f;
			try
			{
				SendRateTuner.Evaluate();
			}
			catch (Exception ex2)
			{
				ManualLogSource logger2 = Plugin.Logger;
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(29, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Send rate evaluation failed: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex2.Message);
				}
				logger2.LogError(val);
			}
		}

		private void LateUpdate()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			try
			{
				WarningHider.Tick();
			}
			catch (Exception ex)
			{
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(24, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Hiding warnings failed: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				logger.LogError(val);
			}
		}
	}
	[BepInPlugin("kamiloo13.bigwalk.direct-connect", "Direct Connect", "1.0.0")]
	public sealed class Plugin : BasePlugin
	{
		public const string Guid = "kamiloo13.bigwalk.direct-connect";

		public const string Name = "Direct Connect";

		public const string Version = "1.0.0";

		internal static ManualLogSource Logger;

		internal static ConfigEntry<string> Language;

		internal static ConfigEntry<TuningMode> Mode;

		internal static ConfigEntry<int> SendRate;

		internal static ConfigEntry<bool> FlushKcp;

		internal static ConfigEntry<string> HideWarningsKey;

		internal static ConfigEntry<bool> HideWarningsOnStart;

		public override void Load()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_0031: 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: Expected O, but got Unknown
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			Logger = ((BasePlugin)this).Log;
			BindConfig();
			ClassInjector.RegisterTypeInIl2Cpp<ModController>();
			GameObject val = new GameObject("DirectConnectController");
			Object.DontDestroyOnLoad((Object)val);
			val.AddComponent<ModController>();
			Harmony val2 = new Harmony("kamiloo13.bigwalk.direct-connect");
			val2.PatchAll();
			KcpFlusher.Install(val2);
			if (HideWarningsOnStart.Value)
			{
				WarningHider.SetHidden(hidden: true);
			}
			ManualLogSource logger = Logger;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(56, 4, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("Loaded. Mode=");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<TuningMode>(Mode.Value);
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(", SendRate=");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(SendRate.Value);
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" Hz, FlushKcp=");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<bool>(FlushKcp.Value);
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(", ");
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("hide warnings: ");
				((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(HideWarningsKey.Value);
				((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(".");
			}
			logger.LogInfo(val3);
		}

		private void BindConfig()
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			Language = ((BasePlugin)this).Config.Bind<string>("General", "Language", "auto", "Language of the mod's texts. 'auto' follows the game's language (falls back to the system language). Or force one of: " + string.Join(", ", Translations.Codes) + ".");
			Mode = ((BasePlugin)this).Config.Bind<TuningMode>("Network", "SendRateMode", TuningMode.DirectIpOnly, "When to raise the send rate. DirectIpOnly = only when connected by IP (client) / when every remote player is connected by IP (host). Always = every session (players without the mod may see jittery movement). Off = never.");
			SendRate = ((BasePlugin)this).Config.Bind<int>("Network", "SendRate", 60, new ConfigDescription("Mirror send rate in Hz (game default: 30). All players should use the same value.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(30, 120), Array.Empty<object>()));
			FlushKcp = ((BasePlugin)this).Config.Bind<bool>("Network", "FlushKcpEveryFrame", true, "Flush KCP reliable data every frame instead of every 10 ms. Works without the mod on the other side.");
			HideWarningsKey = ((BasePlugin)this).Config.Bind<string>("Warnings", "ToggleKey", "F5", "Key that shows/hides the game's warning banners, e.g. 'No network connection' (Unity KeyCode name: F5, F6, Insert, ...).");
			HideWarningsOnStart = ((BasePlugin)this).Config.Bind<bool>("Warnings", "HiddenOnStart", false, "Hide warning banners from the start, without pressing the key first.");
		}
	}
}
namespace BigWalk.DirectConnect.Warnings
{
	internal static class KeyInput
	{
		private static bool _initialized;

		private static MethodInfo _legacyGetKeyDown;

		private static Type _keyCodeType;

		private static bool _legacyFailed;

		private static PropertyInfo _keyboardCurrent;

		public static bool WasPressed(string keyName)
		{
			if (string.IsNullOrWhiteSpace(keyName))
			{
				return false;
			}
			if (!_initialized)
			{
				Initialize();
			}
			if (!LegacyPressed(keyName))
			{
				return InputSystemPressed(keyName);
			}
			return true;
		}

		private static void Initialize()
		{
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			_initialized = true;
			Type type = Reflect.FindType("UnityEngine.Input");
			_keyCodeType = Reflect.FindType("UnityEngine.KeyCode");
			if (type != null && _keyCodeType != null)
			{
				_legacyGetKeyDown = type.GetMethod("GetKeyDown", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { _keyCodeType }, null);
			}
			_keyboardCurrent = Reflect.FindType("UnityEngine.InputSystem.Keyboard")?.GetProperty("current", BindingFlags.Static | BindingFlags.Public);
			ManualLogSource logger = Plugin.Logger;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(53, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Keyboard input: legacy Input Manager=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(_legacyGetKeyDown != null);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", Input System=");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<bool>(_keyboardCurrent != null);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
			}
			logger.LogInfo(val);
		}

		private static bool LegacyPressed(string keyName)
		{
			if (_legacyGetKeyDown == null || _legacyFailed)
			{
				return false;
			}
			try
			{
				object obj = Enum.Parse(_keyCodeType, keyName, ignoreCase: true);
				return (bool)_legacyGetKeyDown.Invoke(null, new object[1] { obj });
			}
			catch (ArgumentException)
			{
				return false;
			}
			catch
			{
				_legacyFailed = true;
				return false;
			}
		}

		private static bool InputSystemPressed(string keyName)
		{
			if (_keyboardCurrent == null)
			{
				return false;
			}
			try
			{
				object value = _keyboardCurrent.GetValue(null);
				if (value == null)
				{
					return false;
				}
				string name = char.ToLowerInvariant(keyName[0]) + keyName.Substring(1) + "Key";
				object obj = value.GetType().GetProperty(name, BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public)?.GetValue(value);
				object obj2 = obj?.GetType().GetProperty("wasPressedThisFrame")?.GetValue(obj);
				bool flag = default(bool);
				int num;
				if (obj2 is bool)
				{
					flag = (bool)obj2;
					num = 1;
				}
				else
				{
					num = 0;
				}
				return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
			}
			catch
			{
				return false;
			}
		}
	}
	internal static class WarningHider
	{
		private sealed class HiddenBanner
		{
			public readonly CanvasGroup Group;

			public readonly float OriginalAlpha;

			public readonly bool OriginalBlocksRaycasts;

			public readonly bool AddedByMod;

			public HiddenBanner(CanvasGroup group, float originalAlpha, bool originalBlocksRaycasts, bool addedByMod)
			{
				Group = group;
				OriginalAlpha = originalAlpha;
				OriginalBlocksRaycasts = originalBlocksRaycasts;
				AddedByMod = addedByMod;
			}
		}

		private const float ScanInterval = 0.25f;

		private const int MaxAncestorDepth = 4;

		private static readonly string[] WarningWords = new string[23]
		{
			"WARNING", "UWAGA", "ACHTUNG", "ATTENTION", "AVERTISSEMENT", "ATENCIÓN", "ADVERTENCIA", "ATTENZIONE", "AVVISO", "AVISO",
			"ATENÇÃO", "ВНИМАНИЕ", "ПРЕДУПРЕЖДЕНИЕ", "УВАГА", "ПОПЕРЕДЖЕННЯ", "VAROVÁNÍ", "POZOR", "UYARI", "DİKKAT", "警告",
			"注意", "경고", "주의"
		};

		private static readonly Regex RichTextTags = new Regex("<[^>]*>", RegexOptions.Compiled);

		private static readonly List<HiddenBanner> Banners = new List<HiddenBanner>();

		private static float _nextScan;

		public static bool Hidden { get; private set; }

		public static void HandleToggleKey()
		{
			if (KeyInput.WasPressed(Plugin.HideWarningsKey.Value))
			{
				SetHidden(!Hidden);
			}
		}

		public static void SetHidden(bool hidden)
		{
			Hidden = hidden;
			if (hidden)
			{
				Scan(logResult: true);
				Plugin.Logger.LogInfo((object)"Warning banners: hidden.");
			}
			else
			{
				RestoreAll();
				Plugin.Logger.LogInfo((object)"Warning banners: visible.");
			}
		}

		public static void Tick()
		{
			if (!Hidden)
			{
				return;
			}
			if (Time.unscaledTime >= _nextScan)
			{
				_nextScan = Time.unscaledTime + 0.25f;
				Scan(logResult: false);
			}
			Banners.RemoveAll((HiddenBanner b) => (Object)(object)b.Group == (Object)null);
			foreach (HiddenBanner banner in Banners)
			{
				banner.Group.alpha = 0f;
				banner.Group.blocksRaycasts = false;
			}
		}

		private static void Scan(bool logResult)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			int num = 0;
			bool flag = default(bool);
			foreach (TMP_Text item in Object.FindObjectsByType<TMP_Text>((FindObjectsSortMode)0))
			{
				if ((Object)(object)item == (Object)null || !IsWarningText(item.text))
				{
					continue;
				}
				Transform val = FindBannerRoot(item.transform);
				if (Hide(val) && logResult)
				{
					ManualLogSource logger = Plugin.Logger;
					BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(28, 2, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Hiding banner '");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(PathOf(val));
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("' (text: \"");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(Plain(item.text));
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("\").");
					}
					logger.LogInfo(val2);
				}
				num++;
			}
			if (logResult && num == 0)
			{
				Plugin.Logger.LogInfo((object)"No warning banner is on screen right now; new ones will be hidden as they appear.");
			}
		}

		private static bool IsWarningText(string text)
		{
			if (string.IsNullOrEmpty(text))
			{
				return false;
			}
			string plain = Plain(text).ToUpperInvariant();
			return WarningWords.Any((string word) => plain.StartsWith(word, StringComparison.Ordinal));
		}

		private static Transform FindBannerRoot(Transform label)
		{
			Transform val = label;
			for (int i = 0; i <= 4; i++)
			{
				if (!((Object)(object)val != (Object)null))
				{
					break;
				}
				foreach (Component component in ((Component)val).GetComponents<Component>())
				{
					if ((Object)(object)component != (Object)null && ((MemberInfo)((Object)component).GetIl2CppType()).Name.IndexOf("Warning", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						return val;
					}
				}
				val = val.parent;
			}
			if (!((Object)(object)label.parent != (Object)null))
			{
				return label;
			}
			return label.parent;
		}

		private static bool Hide(Transform root)
		{
			CanvasGroup group = ((Component)root).GetComponent<CanvasGroup>();
			bool flag = (Object)(object)group == (Object)null;
			if (flag)
			{
				group = ((Component)root).gameObject.AddComponent<CanvasGroup>();
			}
			if (Banners.Any((HiddenBanner b) => (Object)(object)b.Group != (Object)null && ((Il2CppObjectBase)b.Group).Pointer == ((Il2CppObjectBase)group).Pointer))
			{
				return false;
			}
			Banners.Add(new HiddenBanner(group, group.alpha, group.blocksRaycasts, flag));
			group.alpha = 0f;
			group.blocksRaycasts = false;
			return true;
		}

		private static void RestoreAll()
		{
			foreach (HiddenBanner banner in Banners)
			{
				if (!((Object)(object)banner.Group == (Object)null))
				{
					if (banner.AddedByMod)
					{
						Object.Destroy((Object)(object)banner.Group);
						continue;
					}
					banner.Group.alpha = banner.OriginalAlpha;
					banner.Group.blocksRaycasts = banner.OriginalBlocksRaycasts;
				}
			}
			Banners.Clear();
		}

		private static string Plain(string text)
		{
			return RichTextTags.Replace(text ?? "", "").Replace('\n', ' ').Trim();
		}

		private static string PathOf(Transform t)
		{
			StringBuilder stringBuilder = new StringBuilder(((Object)t).name);
			Transform parent = t.parent;
			while ((Object)(object)parent != (Object)null)
			{
				stringBuilder.Insert(0, ((Object)parent).name + "/");
				parent = parent.parent;
			}
			return stringBuilder.ToString();
		}
	}
}
namespace BigWalk.DirectConnect.UI
{
	internal static class InputFields
	{
		public static void Reset(TMP_InputField field, ContentType type, int characterLimit, Action<string> onSubmit)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Expected O, but got Unknown
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			field.text = string.Empty;
			field.onSubmit = new SubmitEvent();
			field.onEndEdit = new SubmitEvent();
			field.onValueChanged = new OnChangeEvent();
			field.onSelect = new SelectionEvent();
			field.onDeselect = new SelectionEvent();
			field.onValidateInput = null;
			field.inputValidator = null;
			field.lineType = (LineType)0;
			field.contentType = type;
			field.characterLimit = characterLimit;
			((UnityEvent<string>)(object)field.onSubmit).AddListener(DelegateSupport.ConvertDelegate<UnityAction<string>>((Delegate)onSubmit));
			field.ForceLabelUpdate();
		}

		public static void SetPlaceholder(TMP_InputField field, string value)
		{
			if (!((Object)(object)field == (Object)null) && !((Object)(object)field.placeholder == (Object)null))
			{
				TMP_Text component = ((Component)field.placeholder).GetComponent<TMP_Text>();
				if ((Object)(object)component != (Object)null)
				{
					component.text = value;
				}
			}
		}

		public static void ShowError(TMP_InputField field, string message)
		{
			if (!((Object)(object)field == (Object)null))
			{
				field.text = string.Empty;
				SetPlaceholder(field, message);
				((Selectable)field).Select();
			}
		}
	}
	internal static class IpJoinSection
	{
		private const string SectionName = "IpJoinSection";

		private const string PasswordName = "IpJoinPassword";

		private const string HeadingPath = "Subheading";

		private const string PlayButtonPath = "PlayButton";

		private const string PlayLabelPath = "PlayButton/Text (TMP)";

		private const int AddressCharacterLimit = 253;

		private const int PasswordCharacterLimit = 32;

		private const float BusyAlpha = 0.5f;

		private const float DotsFrameSeconds = 0.35f;

		private static readonly Action JoinAction = OnJoinClicked;

		private static readonly Action<string> SubmitAction = delegate
		{
			OnJoinClicked();
		};

		private static JoinMenu _pendingMenu;

		private static int _framesToWait;

		private static JoinMenu _menu;

		private static TMP_InputField _addressField;

		private static TMP_InputField _passwordField;

		private static TMP_Text _heading;

		private static TMP_Text _buttonLabel;

		private static CanvasGroup _group;

		private static bool _busy;

		private static string _buttonIcon;

		private static readonly Regex IconMarkup = new Regex("<font=[^>]*>.*?</font>", RegexOptions.IgnoreCase | RegexOptions.Singleline);

		public static void Schedule(JoinMenu menu)
		{
			_pendingMenu = menu;
			_framesToWait = 2;
		}

		public static void Tick()
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Expected O, but got Unknown
			AnimateBusyLabel();
			if ((Object)(object)_pendingMenu == (Object)null)
			{
				return;
			}
			if (!((Component)_pendingMenu).gameObject.activeInHierarchy)
			{
				_pendingMenu = null;
			}
			else
			{
				if (--_framesToWait > 0)
				{
					return;
				}
				JoinMenu pendingMenu = _pendingMenu;
				_pendingMenu = null;
				try
				{
					Setup(pendingMenu);
				}
				catch (Exception ex)
				{
					ManualLogSource logger = Plugin.Logger;
					bool flag = default(bool);
					BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(44, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Failed to set up the 'Join via IP' section: ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
					}
					logger.LogError(val);
				}
			}
		}

		private static void Setup(JoinMenu menu)
		{
			_menu = menu;
			Loc.Refresh();
			TMP_InputField addressField = menu.addressField;
			if ((Object)(object)addressField == (Object)null)
			{
				Plugin.Logger.LogWarning((object)"JoinMenu.addressField is missing; skipping.");
				return;
			}
			Transform parent = ((Component)addressField).transform.parent;
			Transform obj = parent.Find("PlayButton/Text (TMP)");
			_buttonIcon = ExtractIcon((obj != null) ? ((Component)obj).GetComponent<TMP_Text>() : null);
			Transform val = parent.parent.Find("IpJoinSection");
			if ((Object)(object)val == (Object)null)
			{
				val = Build(parent, addressField);
			}
			Bind(val, ((Object)addressField).name);
			SetBusy(AddressResolver.Busy);
			ApplyTexts();
		}

		private static Transform Build(Transform codeBlock, TMP_InputField codeField)
		{
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Expected O, but got Unknown
			//IL_01bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Expected O, but got Unknown
			Canvas.ForceUpdateCanvases();
			Transform parent = codeBlock.parent;
			YRange yRange = UiLayout.VisualRange(codeBlock, parent);
			YRange range;
			float num = (((Object)(object)UiLayout.NearestBelow(parent, yRange.Min, codeBlock, out range) != (Object)null) ? Mathf.Clamp(yRange.Min - range.Max, 0f, 200f) : 24f);
			float num2 = yRange.Height + num;
			Transform transform = UiLayout.CloneInactive(((Component)codeBlock).gameObject, parent).transform;
			((Object)transform).name = "IpJoinSection";
			((Component)transform).gameObject.AddComponent<CanvasGroup>();
			transform.SetSiblingIndex(codeBlock.GetSiblingIndex() + 1);
			TMP_InputField component = ((Component)transform.Find(((Object)codeField).name)).GetComponent<TMP_InputField>();
			InputFields.Reset(component, (ContentType)0, 253, SubmitAction);
			foreach (Button componentsInChild in ((Component)transform).GetComponentsInChildren<Button>(true))
			{
				componentsInChild.onClick = new ButtonClickedEvent();
			}
			Transform val = transform.Find("PlayButton");
			Button val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<Button>() : ((Component)transform).GetComponentInChildren<Button>(true));
			if ((Object)(object)val2 != (Object)null)
			{
				((UnityEvent)val2.onClick).AddListener(DelegateSupport.ConvertDelegate<UnityAction>((Delegate)JoinAction));
			}
			Transform obj = transform.Find("PlayButton/Text (TMP)");
			TMP_Text val3 = ((obj != null) ? ((Component)obj).GetComponent<TMP_Text>() : null);
			if ((Object)(object)val3 != (Object)null)
			{
				val3.fontSizeMax = val3.fontSize;
				val3.fontSizeMin = val3.fontSize * 0.6f;
				val3.enableAutoSizing = true;
			}
			float num3 = AddPasswordField(transform, component);
			UiLayout.PushDown(parent, yRange.Min, num2 + num3, codeBlock, transform);
			transform.position -= parent.TransformVector(new Vector3(0f, num2, 0f));
			ManualLogSource logger = Plugin.Logger;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val4 = new BepInExInfoLogInterpolatedStringHandler(41, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("Added 'Join via IP' section (offset ");
				((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<float>(num2, "0.#");
				((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(" + ");
				((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<float>(num3, "0.#");
				((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(").");
			}
			logger.LogInfo(val4);
			return transform;
		}

		private static float AddPasswordField(Transform section, TMP_InputField address)
		{
			//IL_0085: 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_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			YRange yRange = UiLayout.OwnRange(((Component)address).transform, section);
			float num = yRange.Height + Mathf.Max(12f, yRange.Height * 0.15f);
			UiLayout.PushDown(section, yRange.Min, num, ((Component)address).transform);
			GameObject obj = Object.Instantiate<GameObject>(((Component)address).gameObject, section, false);
			((Object)obj).name = "IpJoinPassword";
			obj.transform.SetSiblingIndex(((Component)address).transform.GetSiblingIndex() + 1);
			obj.transform.position = ((Component)address).transform.position - section.TransformVector(new Vector3(0f, num, 0f));
			InputFields.Reset(obj.GetComponent<TMP_InputField>(), (ContentType)7, 32, SubmitAction);
			return num;
		}

		private static void Bind(Transform section, string addressFieldName)
		{
			Transform obj = section.Find(addressFieldName);
			_addressField = ((obj != null) ? ((Component)obj).GetComponent<TMP_InputField>() : null);
			Transform obj2 = section.Find("IpJoinPassword");
			_passwordField = ((obj2 != null) ? ((Component)obj2).GetComponent<TMP_InputField>() : null);
			Transform obj3 = section.Find("Subheading");
			_heading = ((obj3 != null) ? ((Component)obj3).GetComponent<TMP_Text>() : null);
			Transform obj4 = section.Find("PlayButton/Text (TMP)");
			_buttonLabel = ((obj4 != null) ? ((Component)obj4).GetComponent<TMP_Text>() : null);
			_group = ((Component)section).GetComponent<CanvasGroup>();
		}

		private static void ApplyTexts()
		{
			LocStrings current = Loc.Current;
			if ((Object)(object)_heading != (Object)null)
			{
				_heading.text = current.Heading;
			}
			SetButtonLabel(_buttonIcon);
			InputFields.SetPlaceholder(_addressField, current.AddressPlaceholder);
			InputFields.SetPlaceholder(_passwordField, current.PasswordPlaceholder);
		}

		private static void SetButtonLabel(string suffix)
		{
			if (!((Object)(object)_buttonLabel == (Object)null))
			{
				string button = Loc.Current.Button;
				_buttonLabel.text = (string.IsNullOrEmpty(suffix) ? button : (button + " " + suffix));
			}
		}

		private static void SetBusy(bool busy)
		{
			_busy = busy;
			if ((Object)(object)_group != (Object)null)
			{
				_group.alpha = (busy ? 0.5f : 1f);
				_group.interactable = !busy;
			}
			if (busy)
			{
				TMP_InputField addressField = _addressField;
				if (addressField != null)
				{
					addressField.DeactivateInputField(false);
				}
				TMP_InputField passwordField = _passwordField;
				if (passwordField != null)
				{
					passwordField.DeactivateInputField(false);
				}
			}
			else
			{
				SetButtonLabel(_buttonIcon);
			}
		}

		private static void AnimateBusyLabel()
		{
			if (_busy && !((Object)(object)_buttonLabel == (Object)null))
			{
				int num = (int)(Time.unscaledTime / 0.35f) % 3;
				SetButtonLabel(new string('.', num + 1).PadRight(3));
			}
		}

		private static string ExtractIcon(TMP_Text label)
		{
			if ((Object)(object)label == (Object)null || string.IsNullOrEmpty(label.text))
			{
				return null;
			}
			Match match = IconMarkup.Match(label.text);
			if (!match.Success)
			{
				return null;
			}
			return match.Value;
		}

		private static void OnJoinClicked()
		{
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Expected O, but got Unknown
			if ((Object)(object)_menu == (Object)null || (Object)(object)_addressField == (Object)null || (Object)(object)_passwordField == (Object)null || AddressResolver.Busy)
			{
				return;
			}
			string address;
			AddressKind addressKind = AddressResolver.Classify(_addressField.text, out address);
			if (addressKind == AddressKind.Invalid)
			{
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(26, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Rejected invalid address: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(_addressField.text);
				}
				logger.LogWarning(val);
				InputFields.ShowError(_addressField, Loc.Current.InvalidAddress);
				return;
			}
			string password = _passwordField.text;
			if (string.IsNullOrEmpty(password))
			{
				InputFields.ShowError(_passwordField, Loc.Current.PasswordRequired);
				return;
			}
			if (addressKind == AddressKind.IpAddress)
			{
				DirectJoin.Join(_menu, address, password);
				return;
			}
			JoinMenu menu = _menu;
			SetBusy(busy: true);
			AddressResolver.Resolve(address, delegate(string ip)
			{
				SetBusy(busy: false);
				if ((Object)(object)menu != (Object)null && ((Component)menu).gameObject.activeInHierarchy)
				{
					DirectJoin.Join(menu, ip, password);
				}
			}, delegate
			{
				SetBusy(busy: false);
				InputFields.ShowError(_addressField, Loc.Current.HostNotFound);
			});
		}
	}
	[HarmonyPatch(typeof(JoinMenu), "OnEnable")]
	internal static class JoinMenuOnEnablePatch
	{
		private static void Postfix(JoinMenu __instance)
		{
			try
			{
				IpJoinSection.Schedule(__instance);
			}
			catch (Exception ex)
			{
				Plugin.Logger.LogError((object)ex);
			}
		}
	}
	internal struct YRange
	{
		public float Min;

		public float Max;

		public float Height => Max - Min;

		public YRange(float min, float max)
		{
			Min = min;
			Max = max;
		}
	}
	internal static class UiLayout
	{
		private static readonly Il2CppStructArray<Vector3> Corners = new Il2CppStructArray<Vector3>(4L);

		public static YRange VisualRange(Transform t, Transform space)
		{
			bool flag = false;
			YRange result = new YRange(float.MaxValue, float.MinValue);
			foreach (Graphic componentsInChild in ((Component)t).GetComponentsInChildren<Graphic>(false))
			{
				YRange yRange = OwnRange(((Component)componentsInChild).transform, space);
				result.Min = Mathf.Min(result.Min, yRange.Min);
				result.Max = Mathf.Max(result.Max, yRange.Max);
				flag = true;
			}
			if (!flag)
			{
				return OwnRange(t, space);
			}
			return result;
		}

		public static YRange OwnRange(Transform t, Transform space)
		{
			//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_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			RectTransform component = ((Component)t).GetComponent<RectTransform>();
			if ((Object)(object)component == (Object)null)
			{
				float y = space.InverseTransformPoint(t.position).y;
				return new YRange(y, y);
			}
			component.GetWorldCorners(Corners);
			YRange result = new YRange(float.MaxValue, float.MinValue);
			for (int i = 0; i < 4; i++)
			{
				float y2 = space.InverseTransformPoint(((Il2CppArrayBase<Vector3>)(object)Corners)[i]).y;
				result.Min = Mathf.Min(result.Min, y2);
				result.Max = Mathf.Max(result.Max, y2);
			}
			return result;
		}

		public static Transform NearestBelow(Transform container, float y, Transform skip, out YRange range)
		{
			Transform val = null;
			range = default(YRange);
			for (int i = 0; i < container.childCount; i++)
			{
				Transform child = container.GetChild(i);
				if (!((Object)(object)child == (Object)(object)skip) && ((Component)child).gameObject.activeInHierarchy)
				{
					YRange yRange = VisualRange(child, container);
					if (yRange.Max <= y + 1f && ((Object)(object)val == (Object)null || yRange.Max > range.Max))
					{
						val = child;
						range = yRange;
					}
				}
			}
			return val;
		}

		public static void PushDown(Transform parent, float belowY, float amount, params Transform[] skip)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_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)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = parent.TransformVector(new Vector3(0f, amount, 0f));
			for (int i = 0; i < parent.childCount; i++)
			{
				Transform child = parent.GetChild(i);
				if (Array.IndexOf(skip, child) < 0 && VisualRange(child, parent).Max <= belowY + 1f)
				{
					child.position -= val;
				}
			}
		}

		public static GameObject CloneInactive(GameObject source, Transform parent)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			GameObject val = new GameObject("DirectConnectHolder");
			val.SetActive(false);
			val.transform.SetParent(parent, false);
			GameObject val2 = Object.Instantiate<GameObject>(source, val.transform, false);
			List<Component> list = new List<Component>();
			foreach (Component componentsInChild in val2.GetComponentsInChildren<Component>(true))
			{
				if ((Object)(object)componentsInChild != (Object)null && ((MemberInfo)((Object)componentsInChild).GetIl2CppType()).Name.IndexOf("Locali", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					list.Add(componentsInChild);
				}
			}
			foreach (Component item in list)
			{
				Object.DestroyImmediate((Object)(object)item);
			}
			val2.transform.SetParent(parent, false);
			Object.Destroy((Object)(object)val);
			return val2;
		}
	}
}
namespace BigWalk.DirectConnect.Tuning
{
	internal static class KcpFlusher
	{
		private const int MaxErrors = 5;

		private static readonly Dictionary<Type, MethodInfo> FlushMethods = new Dictionary<Type, MethodInfo>();

		private static bool _disabled;

		private static int _errors;

		public static bool Active { get; private set; }

		private static bool Enabled
		{
			get
			{
				if (!_disabled)
				{
					return Plugin.FlushKcp.Value;
				}
				return false;
			}
		}

		public static void Install(Harmony harmony)
		{
			Type type = Reflect.FindType("kcp2k.KcpTransport") ?? Reflect.FindType("Il2Cppkcp2k.KcpTransport") ?? Reflect.FindTypeByName("KcpTransport");
			if (type == null)
			{
				Plugin.Logger.LogWarning((object)"KcpTransport not found - KCP flush disabled.");
				return;
			}
			Patch(harmony, type, "ServerLateUpdate", "ServerPostfix");
			Patch(harmony, type, "ClientLateUpdate", "ClientPostfix");
		}

		private static void Patch(Harmony harmony, Type type, string method, string postfix)
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Expected O, but got Unknown
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Expected O, but got Unknown
			MethodInfo method2 = type.GetMethod(method, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
			bool flag = default(bool);
			if (method2 == null)
			{
				ManualLogSource logger = Plugin.Logger;
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(26, 2, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(type.Name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(method);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" not found - not patched.");
				}
				logger.LogWarning(val);
				return;
			}
			try
			{
				MethodInfo method3 = typeof(KcpFlusher).GetMethod(postfix, BindingFlags.Static | BindingFlags.NonPublic);
				harmony.Patch((MethodBase)method2, (HarmonyMethod)null, new HarmonyMethod(method3), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			catch (Exception ex)
			{
				ManualLogSource logger2 = Plugin.Logger;
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(19, 3, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Could not patch ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(type.Name);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(method);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
				}
				logger2.LogWarning(val);
			}
		}

		private static void ServerPostfix(object __instance)
		{
			if (!Enabled)
			{
				return;
			}
			try
			{
				foreach (object item in Reflect.Iterate(Reflect.Get(Reflect.Get(__instance, "server"), "connections")))
				{
					FlushPeer(item);
				}
			}
			catch (Exception e)
			{
				Fail(e);
			}
		}

		private static void ClientPostfix(object __instance)
		{
			if (!Enabled)
			{
				return;
			}
			try
			{
				FlushPeer(Reflect.Get(__instance, "client"));
			}
			catch (Exception e)
			{
				Fail(e);
			}
		}

		private static void FlushPeer(object peer)
		{
			if (peer == null)
			{
				return;
			}
			object obj = Reflect.Get(peer, "kcp") ?? Reflect.Get(Reflect.Get(peer, "peer"), "kcp") ?? Reflect.Get(Reflect.Get(peer, "connection"), "kcp");
			if (obj == null)
			{
				return;
			}
			MethodInfo flush = GetFlush(obj.GetType());
			if (!(flush == null))
			{
				flush.Invoke(obj, null);
				_errors = 0;
				if (!Active)
				{
					Active = true;
					Plugin.Logger.LogInfo((object)"KCP per-frame flush is active.");
				}
			}
		}

		private static MethodInfo GetFlush(Type type)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			if (FlushMethods.TryGetValue(type, out var value))
			{
				return value;
			}
			value = type.GetMethod("Flush", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
			FlushMethods[type] = value;
			if (value == null)
			{
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(36, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(type.FullName);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" has no Flush(); KCP flush inactive.");
				}
				logger.LogWarning(val);
			}
			return value;
		}

		private static void Fail(Exception e)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			if (++_errors >= 5)
			{
				_disabled = true;
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(42, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("KCP flush disabled after repeated errors: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(e.InnerException?.Message ?? e.Message);
				}
				logger.LogWarning(val);
			}
		}
	}
	internal static class SendRateTuner
	{
		private static bool _searched;

		private static Type _server;

		private static Type _client;

		private static Type _manager;

		private static Type _transport;

		private static int? _originalRate;

		private static bool _inSession;

		private static bool _kcpChecked;

		private static float _sessionStart;

		public static void Evaluate()
		{
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Expected O, but got Unknown
			if (!_searched)
			{
				FindTypes();
			}
			if (_server == null)
			{
				return;
			}
			bool flag = Reflect.StaticBool(_server, "active");
			bool flag2 = Reflect.StaticBool(_client, "isConnected");
			double? num = Reflect.Number(Reflect.GetStatic(_server, "tickRate"));
			if (!num.HasValue)
			{
				return;
			}
			int num2 = (int)num.Value;
			if (!flag && !flag2)
			{
				EndSession(num2);
				return;
			}
			if (!_inSession)
			{
				BeginSession(num2);
			}
			string reason;
			bool num3 = ShouldRaise(flag, out reason);
			WarnIfKcpFlushInactive(num3);
			int num4 = (num3 ? Plugin.SendRate.Value : _originalRate.Value);
			if (num2 != num4)
			{
				Apply(num4);
				ManualLogSource logger = Plugin.Logger;
				bool flag3 = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(50, 5, ref flag3);
				if (flag3)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Send rate ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num2);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" -> ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num4);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" Hz (");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(reason);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("). ");
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Now: server=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<object>(Reflect.GetStatic(_server, "tickRate"));
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" Hz, client=");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<object>(Reflect.GetStatic(_client, "sendRate"));
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" Hz.");
				}
				logger.LogInfo(val);
			}
		}

		private static void FindTypes()
		{
			_searched = true;
			_server = Reflect.Mirror("NetworkServer");
			_client = Reflect.Mirror("NetworkClient");
			_manager = Reflect.Mirror("NetworkManager");
			_transport = Reflect.Mirror("Transport");
			if (_server == null)
			{
				Plugin.Logger.LogWarning((object)"Mirror.NetworkServer not found - send rate tuning disabled.");
			}
		}

		private static void BeginSession(int current)
		{
			_inSession = true;
			_sessionStart = Time.unscaledTime;
			_kcpChecked = false;
			int valueOrDefault = _originalRate.GetValueOrDefault();
			if (!_originalRate.HasValue)
			{
				valueOrDefault = current;
				_originalRate = valueOrDefault;
			}
		}

		private static void EndSession(int current)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			if (!_inSession)
			{
				return;
			}
			_inSession = false;
			if (_originalRate.HasValue && current != _originalRate.Value)
			{
				Apply(_originalRate.Value);
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(42, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Session ended - send rate restored to ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(_originalRate.Value);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" Hz.");
				}
				logger.LogInfo(val);
			}
		}

		private static bool ShouldRaise(bool server, out string reason)
		{
			switch (Plugin.Mode.Value)
			{
			case TuningMode.Always:
				reason = "mode Always";
				return true;
			case TuningMode.Off:
				reason = "mode Off";
				return false;
			default:
				return IsDirectSession(server, out reason);
			}
		}

		private static bool IsDirectSession(bool server, out string reason)
		{
			if (!server)
			{
				string text = Reflect.CastToRuntimeType(Reflect.GetStatic(_transport, "active"))?.GetType().Name ?? "unknown";
				reason = "client transport " + text;
				return text.Contains("Kcp");
			}
			int num = 0;
			foreach (object item in Reflect.Iterate(Reflect.GetStatic(_server, "connections")))
			{
				string text2 = Reflect.Get(item, "address") as string;
				if (!string.IsNullOrEmpty(text2) && !(text2 == "localhost"))
				{
					num++;
					if (!IPAddress.TryParse(text2, out IPAddress _))
					{
						reason = "a non-IP (Epic) player is connected";
						return false;
					}
				}
			}
			reason = ((num > 0) ? $"host, {num} IP player(s)" : "host, no remote players");
			return num > 0;
		}

		private static void Apply(int rate)
		{
			Reflect.SetStatic(_server, "tickRate", rate);
			Reflect.SetStatic(_client, "sendRate", rate);
			object o = Reflect.CastToRuntimeType(Reflect.GetStatic(_manager, "singleton"));
			Reflect.Set(o, "sendRate", rate);
			Reflect.Set(o, "serverTickRate", rate);
		}

		private static void WarnIfKcpFlushInactive(bool directSession)
		{
			if (!_kcpChecked && !(Time.unscaledTime - _sessionStart < 10f))
			{
				_kcpChecked = true;
				if (directSession && Plugin.FlushKcp.Value && !KcpFlusher.Active)
				{
					Plugin.Logger.LogWarning((object)"KCP flush found no KCP connection in this session (unknown kcp2k layout?).");
				}
			}
		}
	}
	public enum TuningMode
	{
		DirectIpOnly,
		Always,
		Off
	}
}
namespace BigWalk.DirectConnect.Networking
{
	internal enum AddressKind
	{
		Invalid,
		IpAddress,
		HostName
	}
	internal static class AddressResolver
	{
		private const float TimeoutSeconds = 10f;

		private static Task<IPAddress[]> _pending;

		private static string _pendingHost;

		private static float _startedAt;

		private static Action<string> _onResolved;

		private static Action _onFailed;

		public static bool Busy => _pending != null;

		public static AddressKind Classify(string input, out string address)
		{
			address = (input ?? string.Empty).Trim().TrimStart('[').TrimEnd(']')
				.TrimEnd('.');
			if (address.Length == 0)
			{
				return AddressKind.Invalid;
			}
			if (IPAddress.TryParse(address, out IPAddress address2))
			{
				return address2.AddressFamily switch
				{
					AddressFamily.InterNetwork => (address.Split('.').Length == 4) ? AddressKind.IpAddress : AddressKind.Invalid, 
					AddressFamily.InterNetworkV6 => AddressKind.IpAddress, 
					_ => AddressKind.Invalid, 
				};
			}
			if (Uri.CheckHostName(address) != UriHostNameType.Dns)
			{
				return AddressKind.Invalid;
			}
			return AddressKind.HostName;
		}

		public static void Resolve(string host, Action<string> onResolved, Action onFailed)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Expected O, but got Unknown
			_pendingHost = host;
			_onResolved = onResolved;
			_onFailed = onFailed;
			_startedAt = Time.unscaledTime;
			_pending = Dns.GetHostAddressesAsync(host);
			ManualLogSource logger = Plugin.Logger;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(13, 1, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Resolving ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(host);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("...");
			}
			logger.LogInfo(val);
		}

		public static void Tick()
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Expected O, but got Unknown
			if (_pending == null)
			{
				return;
			}
			bool flag = Time.unscaledTime - _startedAt > 10f;
			if (!_pending.IsCompleted && !flag)
			{
				return;
			}
			Task<IPAddress[]> pending = _pending;
			Action<string> onResolved = _onResolved;
			Action onFailed = _onFailed;
			_pending = null;
			_onResolved = null;
			_onFailed = null;
			IPAddress iPAddress = ((pending.Status == TaskStatus.RanToCompletion) ? Choose(pending.Result) : null);
			if (iPAddress == null)
			{
				Plugin.Logger.LogWarning((object)(flag ? ("Resolving " + _pendingHost + " timed out.") : ("Host " + _pendingHost + " not found.")));
				onFailed?.Invoke();
				return;
			}
			ManualLogSource logger = Plugin.Logger;
			bool flag2 = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(14, 2, ref flag2);
			if (flag2)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Resolved ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(_pendingHost);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" -> ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<IPAddress>(iPAddress);
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
			}
			logger.LogInfo(val);
			onResolved?.Invoke(iPAddress.ToString());
		}

		private static IPAddress Choose(IPAddress[] addresses)
		{
			if (addresses == null || addresses.Length == 0)
			{
				return null;
			}
			return addresses.FirstOrDefault((IPAddress a) => a.AddressFamily == AddressFamily.InterNetwork) ?? addresses.FirstOrDefault((IPAddress a) => a.AddressFamily == AddressFamily.InterNetworkV6);
		}
	}
	internal static class DirectJoin
	{
		public const int Port = 7777;

		public static void Join(JoinMenu menu, string address, string password)
		{
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Expected O, but got Unknown
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Expected O, but got Unknown
			bool flag = default(bool);
			try
			{
				PasswordAutoFill.Arm(password);
				menu.GoToConnectingMenu();
				NetworkMinder.SetTransportAndConnect(address);
				string text = (address.Contains(':') ? $"[{address}]:{7777}" : $"{address}:{7777}");
				ManualLogSource logger = Plugin.Logger;
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(24, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Connecting directly to ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral(".");
				}
				logger.LogInfo(val);
			}
			catch (Exception ex)
			{
				PasswordAutoFill.Disarm();
				ManualLogSource logger2 = Plugin.Logger;
				BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(20, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Join via IP failed: ");
					((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
				}
				logger2.LogError(val2);
			}
		}
	}
	internal static class PasswordAutoFill
	{
		private const float TimeoutSeconds = 60f;

		private static string _password = string.Empty;

		private static bool _armed;

		private static float _armedAt;

		public static void Arm(string password)
		{
			_password = password ?? string.Empty;
			_armed = _password.Length > 0;
			_armedAt = Time.unscaledTime;
		}

		public static void Disarm()
		{
			_armed = false;
			_password = string.Empty;
		}

		public static void Tick()
		{
			if (!_armed)
			{
				return;
			}
			if (Time.unscaledTime - _armedAt > 60f)
			{
				Disarm();
				return;
			}
			MainMenuManager instance = MainMenuManager.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			PasswordMenu passwordMenu = instance.passwordMenu;
			if (!((Object)(object)passwordMenu == (Object)null) && ((Component)passwordMenu).gameObject.activeInHierarchy)
			{
				if ((Object)(object)passwordMenu.passwordField == (Object)null)
				{
					Disarm();
					return;
				}
				passwordMenu.passwordField.text = _password;
				Disarm();
				passwordMenu.SubmitPassword();
				Plugin.Logger.LogInfo((object)"Submitted the password requested by the host.");
			}
		}
	}
}
namespace BigWalk.DirectConnect.Localization
{
	internal static class GameLanguage
	{
		private const BindingFlags Static = BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

		private const BindingFlags Instance = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private static readonly string[] SingletonNames = new string[5] { "instance", "Instance", "singleton", "Singleton", "I" };

		private static bool _searched;

		private static MemberInfo _member;

		private static Type _owner;

		private static string _singletonName;

		public static string Read()
		{
			if (!_searched)
			{
				Search();
			}
			if (_member == null)
			{
				return null;
			}
			try
			{
				object obj = ((_singletonName == null) ? null : Reflect.GetStatic(_owner, _singletonName));
				if (_singletonName != null && obj == null)
				{
					return null;
				}
				return ((_member is PropertyInfo propertyInfo) ? propertyInfo.GetValue(obj) : ((FieldInfo)_member).GetValue(obj))?.ToString();
			}
			catch
			{
				return null;
			}
		}

		private static void Search()
		{
			_searched = true;
			int bestScore = 0;
			foreach (Type item in Reflect.AllTypes())
			{
				if (!(item.Assembly.GetName().Name != "Assembly-CSharp") && (item.Name.IndexOf("Locali", StringComparison.OrdinalIgnoreCase) >= 0 || item.Name.IndexOf("Language", StringComparison.OrdinalIgnoreCase) >= 0))
				{
					MemberInfo[] properties = item.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					Consider(item, properties, null, ref bestScore);
					properties = item.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
					Consider(item, properties, null, ref bestScore);
					string text = FindSingleton(item);
					if (text != null)
					{
						properties = item.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
						Consider(item, properties, text, ref bestScore);
						properties = item.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
						Consider(item, properties, text, ref bestScore);
					}
				}
			}
			Plugin.Logger.LogInfo((object)((_member == null) ? "Game language setting not found - using the system language (set General.Language in the config to override)." : $"Game language read from {_owner.FullName}{((_singletonName != null) ? ("." + _singletonName) : "")}.{_member.Name}"));
		}

		private static void Consider(Type owner, MemberInfo[] members, string singleton, ref int bestScore)
		{
			foreach (MemberInfo memberInfo in members)
			{
				Type type = ((memberInfo is PropertyInfo propertyInfo) ? propertyInfo.PropertyType : (memberInfo as FieldInfo)?.FieldType);
				if (type == null || (type != typeof(string) && !type.IsEnum))
				{
					continue;
				}
				string text = memberInfo.Name.ToLowerInvariant();
				if (text.Contains("lang") || text.Contains("locale"))
				{
					int num = 1;
					if (text.Contains("current") || text.Contains("selected") || text.Contains("active"))
					{
						num += 2;
					}
					if (text.Contains("default") || text.Contains("fallback") || text.Contains("system") || text.Contains("source"))
					{
						num -= 2;
					}
					if (num > bestScore)
					{
						bestScore = num;
						_member = memberInfo;
						_owner = owner;
						_singletonName = singleton;
					}
				}
			}
		}

		private static string FindSingleton(Type t)
		{
			string[] singletonNames = SingletonNames;
			foreach (string text in singletonNames)
			{
				PropertyInfo property = t.GetProperty(text, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (property != null && t.IsAssignableFrom(property.PropertyType))
				{
					return text;
				}
				FieldInfo field = t.GetField(text, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null && t.IsAssignableFrom(field.FieldType))
				{
					return text;
				}
			}
			return null;
		}
	}
	internal static class LanguageCodes
	{
		private static readonly Dictionary<string, string> Names = new Dictionary<string, string>
		{
			["english"] = "en",
			["polish"] = "pl",
			["german"] = "de",
			["french"] = "fr",
			["spanish"] = "es",
			["italian"] = "it",
			["portuguese"] = "pt",
			["brazilianportuguese"] = "pt",
			["portuguesebrazil"] = "pt",
			["russian"] = "ru",
			["ukrainian"] = "uk",
			["czech"] = "cs",
			["turkish"] = "tr",
			["japanese"] = "ja",
			["korean"] = "ko",
			["chinese"] = "zh-Hans",
			["chinesesimplified"] = "zh-Hans",
			["schinese"] = "zh-Hans",
			["chinesetraditional"] = "zh-Hant",
			["tchinese"] = "zh-Hant"
		};

		public static string Normalize(string raw)
		{
			if (string.IsNullOrWhiteSpace(raw))
			{
				return null;
			}
			string key = new string(raw.Where(char.IsLetter).ToArray()).ToLowerInvariant();
			if (Names.TryGetValue(key, out var value))
			{
				return value;
			}
			string text = raw.Trim().Replace('_', '-').ToLowerInvariant();
			if (text.StartsWith("zh"))
			{
				if (!text.Contains("hant") && !text.Contains("tw") && !text.Contains("hk") && !text.Contains("mo"))
				{
					return "zh-Hans";
				}
				return "zh-Hant";
			}
			int num = text.IndexOf('-');
			if (num <= 0)
			{
				return text;
			}
			return text.Substring(0, num);
		}

		public static string FromSystemLanguage(SystemLanguage lang)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Invalid comparison between Unknown and I4
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Invalid comparison between Unknown and I4
			//IL_0021: 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_007e: Expected I4, but got Unknown
			if ((int)lang <= 7)
			{
				if ((int)lang != 6)
				{
					if ((int)lang != 7)
					{
						goto IL_00f0;
					}
					return "cs";
				}
			}
			else
			{
				if ((int)lang == 14)
				{
					return "fr";
				}
				if ((int)lang == 15)
				{
					return "de";
				}
				switch (lang - 21)
				{
				case 6:
					return "pl";
				case 13:
					return "es";
				case 0:
					return "it";
				case 7:
					return "pt";
				case 9:
					return "ru";
				case 17:
					return "uk";
				case 16:
					return "tr";
				case 1:
					return "ja";
				case 2:
					return "ko";
				case 20:
					return "zh-Hant";
				case 19:
					break;
				default:
					goto IL_00f0;
				}
			}
			return "zh-Hans";
			IL_00f0:
			return "en";
		}
	}
	internal static class Loc
	{
		private static string _currentCode;

		public static LocStrings Current { get; private set; } = English();

		public static void Refresh()
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			bool flag = default(bool);
			foreach (var item3 in Candidates())
			{
				string item = item3.source;
				string item2 = item3.raw;
				string text = LanguageCodes.Normalize(item2);
				if (text == null || !Translations.TryGet(text, out var strings))
				{
					continue;
				}
				Current = strings;
				if (text != _currentCode)
				{
					_currentCode = text;
					ManualLogSource logger = Plugin.Logger;
					BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(27, 3, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Language: '");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(item2);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' (from ");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(item);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral(") -> '");
						((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
						((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'.");
					}
					logger.LogInfo(val);
				}
				return;
			}
			Current = English();
		}

		private static IEnumerable<(string source, string raw)> Candidates()
		{
			string value = Plugin.Language.Value;
			if (!string.IsNullOrWhiteSpace(value) && !value.Equals("auto", StringComparison.OrdinalIgnoreCase))
			{
				yield return (source: "config", raw: value);
			}
			string text = GameLanguage.Read();
			if (text != null)
			{
				yield return (source: "game", raw: text);
			}
			yield return (source: "system", raw: LanguageCodes.FromSystemLanguage(Application.systemLanguage));
		}

		private static LocStrings English()
		{
			Translations.TryGet("en", out var strings);
			return strings;
		}
	}
	internal sealed class LocStrings
	{
		public readonly string Heading;

		public readonly string AddressPlaceholder;

		public readonly string PasswordPlaceholder;

		public readonly string Button;

		public readonly string InvalidAddress;

		public readonly string PasswordRequired;

		public readonly string HostNotFound;

		public LocStrings(string heading, string addressPlaceholder, string passwordPlaceholder, string button, string invalidAddress, string passwordRequired, string hostNotFound)
		{
			Heading = heading;
			AddressPlaceholder = addressPlaceholder;
			PasswordPlaceholder = passwordPlaceholder;
			Button = button;
			InvalidAddress = invalidAddress;
			PasswordRequired = passwordRequired;
			HostNotFound = hostNotFound;
		}
	}
	internal static class Translations
	{
		private static readonly Dictionary<string, LocStrings> Table = new Dictionary<string, LocStrings>(StringComparer.OrdinalIgnoreCase)
		{
			["en"] = new LocStrings("JOIN VIA IP:", "IP / domain, e.g. 192.168.1.10, 2001:db8::1", "Password", "Join", "Invalid address", "Enter the password", "Host not found"),
			["pl"] = new LocStrings("DOŁĄCZ PRZEZ IP:", "IP / domena, np. 192.168.1.10, 2001:db8::1", "Hasło", "Dołącz", "Nieprawidłowy adres", "Wpisz hasło", "Nie znaleziono hosta"),
			["de"] = new LocStrings("ÜBER IP BEITRETEN:", "IP / Domain, z. B. 192.168.1.10, 2001:db8::1", "Passwort", "Beitreten", "Ungültige Adresse", "Passwort eingeben", "Host nicht gefunden"),
			["fr"] = new LocStrings("REJOINDRE PAR IP :", "IP / domaine, ex. 192.168.1.10, 2001:db8::1", "Mot de passe", "Rejoindre", "Adresse invalide", "Saisissez le mot de passe", "Hôte introuvable"),
			["es"] = new LocStrings("UNIRSE POR IP:", "IP / dominio, p. ej. 192.168.1.10, 2001:db8::1", "Contraseña", "Unirse", "Dirección no válida", "Introduce la contraseña", "Host no encontrado"),
			["it"] = new LocStrings("UNISCITI TRAMITE IP:", "IP / dominio, es. 192.168.1.10, 2001:db8::1", "Password", "Unisciti", "Indirizzo non valido", "Inserisci la password", "Host non trovato"),
			["pt"] = new LocStrings("ENTRAR POR IP:", "IP / domínio, ex.: 192.168.1.10, 2001:db8::1", "Senha", "Entrar", "Endereço inválido", "Digite a senha", "Host não encontrado"),
			["ru"] = new LocStrings("ПОДКЛЮЧИТЬСЯ ПО IP:", "IP / домен, напр. 192.168.1.10, 2001:db8::1", "Пароль", "Войти", "Неверный адрес", "Введите пароль", "Хост не найден"),
			["uk"] = new LocStrings("ПРИЄДНАТИСЯ ЗА IP:", "IP / домен, напр. 192.168.1.10, 2001:db8::1", "Пароль", "Приєднатися", "Неправильна адреса", "Введіть пароль", "Хост не знайдено"),
			["cs"] = new LocStrings("PŘIPOJIT PŘES IP:", "IP / doména, např. 192.168.1.10, 2001:db8::1", "Heslo", "Připojit", "Neplatná adresa", "Zadejte heslo", "Hostitel nenalezen"),
			["tr"] = new LocStrings("IP İLE KATIL:", "IP / alan adı, ör. 192.168.1.10, 2001:db8::1", "Şifre", "Katıl", "Geçersiz adres", "Şifreyi girin", "Sunucu bulunamadı"),
			["ja"] = new LocStrings("IPで参加:", "IP / ドメイン(例:192.168.1.10、2001:db8::1)", "パスワード", "参加", "無効なアドレス", "パスワードを入力してください", "ホストが見つかりません"),
			["ko"] = new LocStrings("IP로 참가:", "IP / 도메인 (예: 192.168.1.10, 2001:db8::1)", "비밀번호", "참가", "잘못된 주소", "비밀번호를 입력하세요", "호스트를 찾을 수 없습니다"),
			["zh-Hans"] = new LocStrings("通过 IP 加入:", "IP / 域名,例如 192.168.1.10、2001:db8::1", "密码", "加入", "无效的地址", "请输入密码", "找不到主机"),
			["zh-Hant"] = new LocStrings("透過 IP 加入:", "IP / 網域,例如 192.168.1.10、2001:db8::1", "密碼", "加入", "無效的位址", "請輸入密碼", "找不到主機")
		};

		public static IEnumerable<string> Codes => Table.Keys;

		public static bool TryGet(string code, out LocStrings strings)
		{
			return Table.TryGetValue(code ?? "", out strings);
		}
	}
}
namespace BigWalk.DirectConnect.Common
{
	internal static class Reflect
	{
		private const BindingFlags Inst = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private const BindingFlags Stat = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy;

		public static Type FindType(string fullName)
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				try
				{
					Type type = assembly.GetType(fullName, throwOnError: false);
					if (type != null)
					{
						return type;
					}
				}
				catch
				{
				}
			}
			return null;
		}

		public static Type FindTypeByName(string name)
		{
			foreach (Type item in AllTypes())
			{
				if (item.Name == name)
				{
					return item;
				}
			}
			return null;
		}

		public static Type Mirror(string name)
		{
			return FindType("Mirror." + name) ?? FindType("Il2CppMirror." + name);
		}

		public static IEnumerable<Type> AllTypes()
		{
			Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies)
			{
				Type[] types;
				try
				{
					types = assembly.GetTypes();
				}
				catch (ReflectionTypeLoadException ex)
				{
					types = ex.Types;
				}
				catch
				{
					continue;
				}
				Type[] array = types;
				foreach (Type type in array)
				{
					if (type != null)
					{
						yield return type;
					}
				}
			}
		}

		public static object Get(object o, string name)
		{
			if (o == null)
			{
				return null;
			}
			Type type = o.GetType();
			try
			{
				PropertyInfo propertyInfo = Prop(type, name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (propertyInfo != null && propertyInfo.CanRead)
				{
					return propertyInfo.GetValue(o);
				}
				return type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(o);
			}
			catch
			{
				return null;
			}
		}

		public static void Set(object o, string name, object value)
		{
			if (o == null)
			{
				return;
			}
			Type type = o.GetType();
			try
			{
				PropertyInfo propertyInfo = Prop(type, name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (propertyInfo != null && propertyInfo.CanWrite)
				{
					propertyInfo.SetValue(o, Convert.ChangeType(value, propertyInfo.PropertyType));
					return;
				}
				FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field != null && !field.IsInitOnly)
				{
					field.SetValue(o, Convert.ChangeType(value, field.FieldType));
				}
			}
			catch
			{
			}
		}

		public static object GetStatic(Type t, string name)
		{
			if (t == null)
			{
				return null;
			}
			try
			{
				PropertyInfo propertyInfo = Prop(t, name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
				if (propertyInfo != null && propertyInfo.CanRead)
				{
					return propertyInfo.GetValue(null);
				}
				FieldInfo field = t.GetField(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
				if (field != null)
				{
					return field.IsLiteral ? field.GetRawConstantValue() : field.GetValue(null);
				}
			}
			catch
			{
			}
			return null;
		}

		public static void SetStatic(Type t, string name, object value)
		{
			if (t == null)
			{
				return;
			}
			try
			{
				PropertyInfo propertyInfo = Prop(t, name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
				if (propertyInfo != null && propertyInfo.CanWrite)
				{
					propertyInfo.SetValue(null, Convert.ChangeType(value, propertyInfo.PropertyType));
					return;
				}
				FieldInfo field = t.GetField(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
				if (field != null && !field.IsLiteral && !field.IsInitOnly)
				{
					field.SetValue(null, Convert.ChangeType(value, field.FieldType));
				}
			}
			catch
			{
			}
		}

		public static bool StaticBool(Type t, string name)
		{
			object obj = GetStatic(t, name);
			bool flag = default(bool);
			int num;
			if (obj is bool)
			{
				flag = (bool)obj;
				num = 1;
			}
			else
			{
				num = 0;
			}
			return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		}

		public static double? Number(object o)
		{
			if (o == null)
			{
				return null;
			}
			try
			{
				return Convert.ToDouble(o);
			}
			catch
			{
				return null;
			}
		}

		public static object CastToRuntimeType(object o)
		{
			Object val = (Object)((o is Object) ? o : null);
			if (val == null)
			{
				return o;
			}
			try
			{
				string fullName = val.GetIl2CppType().FullName;
				Type type = FindType(fullName) ?? FindType("Il2Cpp" + fullName);
				if (type == null || type == o.GetType())
				{
					return o;
				}
				return typeof(Il2CppObjectBase).GetMethod("TryCast").MakeGenericMethod(type).Invoke(o, null) ?? o;
			}
			catch
			{
				return o;
			}
		}

		public static IEnumerable<object> Iterate(object collection)
		{
			if (collection == null)
			{
				yield break;
			}
			object obj = Get(collection, "Values") ?? collection;
			if (obj is IEnumerable enumerable && !(obj is string))
			{
				foreach (object item in enumerable)
				{
					yield return item;
				}
				yield break;
			}
			object enumerator2 = obj.GetType().GetMethod("GetEnumerator", Type.EmptyTypes)?.Invoke(obj, null);
			if (enumerator2 == null)
			{
				yield break;
			}
			MethodInfo moveNext = enumerator2.GetType().GetMethod("MoveNext", Type.EmptyTypes);
			PropertyInfo current = enumerator2.GetType().GetProperty("Current");
			if (!(moveNext == null) && !(current == null))
			{
				while ((bool)moveNext.Invoke(enumerator2, null))
				{
					yield return current.GetValue(enumerator2);
				}
			}
		}

		private static PropertyInfo Prop(Type t, string name, BindingFlags flags)
		{
			try
			{
				PropertyInfo property = t.GetProperty(name, flags);
				return (property != null && property.GetIndexParameters().Length == 0) ? property : null;
			}
			catch (AmbiguousMatchException)
			{
				PropertyInfo[] properties = t.GetProperties(flags);
				foreach (PropertyInfo propertyInfo in properties)
				{
					if (propertyInfo.Name == name && propertyInfo.GetIndexParameters().Length == 0)
					{
						return propertyInfo;
					}
				}
				return null;
			}
		}
	}
}