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;
}
}
}
}