Decompiled source of Baby Steps Multiplayer Mod v1.3.2

Mods/BabyStepsMenuLib.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using HarmonyLib;
using Il2Cpp;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppTMPro;
using MelonLoader;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("Caleb Orchard")]
[assembly: AssemblyConfiguration("Retail - Debug")]
[assembly: AssemblyDescription("A reusable menu injection library for Baby Steps MelonLoader mods.")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+11a490c829d6b67512aa6da54556de709c4ef3c3")]
[assembly: AssemblyProduct("BabyStepsMenuLib")]
[assembly: AssemblyTitle("BabyStepsMenuLib")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/caleborchard/BabyStepsMenuLib")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 BabyStepsMenuLib
{
	public static class MenuInjectionLibrary
	{
		public sealed class RuntimeTabMenu
		{
			private readonly string[] _tabNames;

			private readonly List<Selectable>[] _pageSelectables;

			private int _setTabFrame = -1;

			private Selectable[] _fixedItems;

			public RectTransform Root { get; internal set; }

			public RectTransform Header { get; internal set; }

			public Button[] Tabs { get; internal set; }

			public RectTransform[] Pages { get; internal set; }

			public int ActiveTab { get; private set; }

			public int TabCount
			{
				get
				{
					Button[] tabs = Tabs;
					return (tabs != null) ? tabs.Length : 0;
				}
			}

			internal MenuItemList ManagedItemList { get; set; }

			internal Color NativeHighlightedColor { get; set; } = TabHighlighted;


			internal void SetFixedMenuItems(params Selectable[] items)
			{
				_fixedItems = items;
			}

			internal RuntimeTabMenu(string[] tabNames)
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				_tabNames = tabNames;
				_pageSelectables = new List<Selectable>[tabNames.Length];
				for (int i = 0; i < tabNames.Length; i++)
				{
					_pageSelectables[i] = new List<Selectable>();
				}
			}

			public RectTransform GetPage(int index)
			{
				return (Pages != null && index >= 0 && index < Pages.Length) ? Pages[index] : null;
			}

			public void UpdateTabName(int index, string name)
			{
				if (_tabNames != null && index >= 0 && index < _tabNames.Length)
				{
					_tabNames[index] = name;
				}
			}

			public void OnShown()
			{
				SetActiveTab(ActiveTab);
			}

			internal void RegisterPageSelectable(int page, Selectable s)
			{
				if (!((Object)(object)s == (Object)null) && _pageSelectables != null && page >= 0 && page < _pageSelectables.Length)
				{
					_pageSelectables[page].Add(s);
				}
			}

			public void SetActiveTab(int index)
			{
				//IL_015f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0158: Unknown result type (might be due to invalid IL or missing references)
				//IL_0164: Unknown result type (might be due to invalid IL or missing references)
				//IL_0187: Unknown result type (might be due to invalid IL or missing references)
				//IL_0194: Unknown result type (might be due to invalid IL or missing references)
				//IL_0213: Unknown result type (might be due to invalid IL or missing references)
				//IL_0218: Unknown result type (might be due to invalid IL or missing references)
				//IL_021c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0227: Unknown result type (might be due to invalid IL or missing references)
				//IL_0235: Unknown result type (might be due to invalid IL or missing references)
				//IL_0243: Unknown result type (might be due to invalid IL or missing references)
				//IL_0250: Unknown result type (might be due to invalid IL or missing references)
				//IL_026e: Unknown result type (might be due to invalid IL or missing references)
				//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
				if (Tabs == null || Pages == null || index < 0 || index >= TabCount)
				{
					return;
				}
				int frameCount = Time.frameCount;
				if (frameCount == _setTabFrame)
				{
					return;
				}
				_setTabFrame = frameCount;
				ActiveTab = index;
				List<Selectable>[] pageSelectables = _pageSelectables;
				List<Selectable> list = ((pageSelectables != null) ? pageSelectables[index] : null);
				for (int i = 0; i < TabCount; i++)
				{
					bool flag = i == index;
					if ((Object)(object)Pages[i] != (Object)null)
					{
						CanvasGroup component = ((Component)Pages[i]).GetComponent<CanvasGroup>();
						if ((Object)(object)component != (Object)null)
						{
							component.alpha = (flag ? 1f : 0f);
							component.interactable = flag;
							component.blocksRaycasts = flag;
						}
						if (flag)
						{
							Il2CppArrayBase<TMP_Text> componentsInChildren = ((Component)Pages[i]).GetComponentsInChildren<TMP_Text>(true);
							for (int j = 0; j < componentsInChildren.Length; j++)
							{
								if ((Object)(object)componentsInChildren[j] != (Object)null)
								{
									componentsInChildren[j].ForceMeshUpdate(false, false);
								}
							}
						}
					}
					if (!((Object)(object)Tabs[i] != (Object)null))
					{
						continue;
					}
					Color val = (flag ? TabSelected : TabUnselected);
					Image component2 = ((Component)Tabs[i]).GetComponent<Image>();
					if ((Object)(object)component2 != (Object)null)
					{
						((Graphic)component2).color = Color.white;
						((Graphic)component2).CrossFadeColor(val, 0f, true, true);
					}
					TMP_Text componentInChildren = ((Component)Tabs[i]).GetComponentInChildren<TMP_Text>(true);
					if ((Object)(object)componentInChildren != (Object)null)
					{
						if (_tabNames != null && i < _tabNames.Length)
						{
							componentInChildren.text = _tabNames[i];
						}
						((Graphic)componentInChildren).color = TabText;
						componentInChildren.ForceMeshUpdate(false, false);
					}
					ColorBlock colors = ((Selectable)Tabs[i]).colors;
					((ColorBlock)(ref colors)).normalColor = val;
					((ColorBlock)(ref colors)).selectedColor = NativeHighlightedColor;
					((ColorBlock)(ref colors)).highlightedColor = NativeHighlightedColor;
					((ColorBlock)(ref colors)).pressedColor = NativeHighlightedColor;
					((ColorBlock)(ref colors)).disabledColor = val;
					((ColorBlock)(ref colors)).colorMultiplier = 1f;
					((Selectable)Tabs[i]).colors = colors;
				}
				int num = list?.Count ?? 0;
				Selectable[] fixedItems = _fixedItems;
				int num2 = ((fixedItems != null) ? fixedItems.Length : 0);
				List<Selectable> list2 = new List<Selectable>(num + num2);
				for (int k = 0; k < num; k++)
				{
					if ((Object)(object)list[k] != (Object)null)
					{
						list2.Add(list[k]);
					}
				}
				for (int l = 0; l < num2; l++)
				{
					if ((Object)(object)_fixedItems[l] != (Object)null)
					{
						list2.Add(_fixedItems[l]);
					}
				}
				if ((Object)(object)ManagedItemList != (Object)null)
				{
					GameObject[] array = (GameObject[])(object)new GameObject[list2.Count];
					for (int m = 0; m < list2.Count; m++)
					{
						array[m] = ((Component)list2[m]).gameObject;
					}
					ManagedItemList.items = Il2CppReferenceArray<GameObject>.op_Implicit(array);
				}
				for (int n = 0; n < list2.Count; n++)
				{
					Selectable val2 = list2[n];
					Navigation navigation = val2.navigation;
					navigation.mode = (Mode)4;
					navigation.selectOnUp = ((n > 0) ? list2[n - 1] : null);
					navigation.selectOnDown = ((n < list2.Count - 1) ? list2[n + 1] : null);
					navigation.selectOnLeft = null;
					navigation.selectOnRight = null;
					val2.navigation = navigation;
				}
			}
		}

		public sealed class TabBuilder
		{
			internal TabBuilder()
			{
			}

			public TMP_Text AddLabel(string text)
			{
				return MenuInjectionLibrary.AddLabel(text, (RectTransform)null);
			}

			public Button AddButton(string text, UnityAction onClick)
			{
				return MenuInjectionLibrary.AddButton(text, onClick, (RectTransform)null);
			}

			public Toggle AddToggle(string text, bool initial, UnityAction<bool> onChange)
			{
				return MenuInjectionLibrary.AddToggle(text, initial, onChange, (RectTransform)null);
			}

			public Slider AddSlider(string text, float min, float max, float value, UnityAction<float> onChange, bool wholeNumbers = false)
			{
				return MenuInjectionLibrary.AddSlider(text, min, max, value, onChange, wholeNumbers, (RectTransform)null);
			}

			public Button AddInputField(string placeholder = "", UnityAction<string> onChange = null, string initialValue = null)
			{
				return MenuInjectionLibrary.AddInputField(placeholder, onChange, initialValue, (RectTransform)null);
			}

			public Image AddImage(Color color, float height = 52f)
			{
				//IL_0000: Unknown result type (might be due to invalid IL or missing references)
				return MenuInjectionLibrary.AddImage(color, height, (RectTransform)null);
			}
		}

		public sealed class MenuBuilder
		{
			internal readonly string _mainButtonLabel;

			internal readonly List<(string name, Action<TabBuilder> configure)> _tabs = new List<(string, Action<TabBuilder>)>();

			internal readonly List<(string label, UnityAction action)> _fixed = new List<(string, UnityAction)>();

			internal float _sideMargin;

			internal float _topMargin;

			internal MenuBuilder(string mainButtonLabel)
			{
				_mainButtonLabel = mainButtonLabel;
			}

			public MenuBuilder AddTab(string name, Action<TabBuilder> configure)
			{
				_tabs.Add((name, configure));
				return this;
			}

			public MenuBuilder AddFixedButton(string label, UnityAction action = null)
			{
				_fixed.Add((label, action));
				return this;
			}

			public MenuBuilder WithMargin(float sideMargin, float topMargin)
			{
				_sideMargin = sideMargin;
				_topMargin = topMargin;
				return this;
			}

			public InjectedMenu Build()
			{
				InjectedMenu injectedMenu = new InjectedMenu(this);
				if (!_registeredMenus.Contains(injectedMenu))
				{
					_registeredMenus.Add(injectedMenu);
				}
				return injectedMenu;
			}
		}

		public sealed class InputFieldInfo
		{
			public string Value = "";

			public TMP_Text DisplayText;

			public UnityAction<string> OnChanged;

			public string Placeholder = "";

			public RectTransform Viewport;

			public Color ActiveColor = Color.white;

			public Color PlaceholderColor = new Color(1f, 1f, 1f, 0.45f);

			public Button OwnerButton;

			public Image CursorImage;
		}

		public sealed class InjectedMenu
		{
			[CompilerGenerated]
			private sealed class <EnforceKeyboardFontSizesCoroutine>d__82 : IEnumerator<object>, IEnumerator, IDisposable
			{
				private int <>1__state;

				private object <>2__current;

				public InjectedMenu <>4__this;

				private int <i>5__1;

				object IEnumerator<object>.Current
				{
					[DebuggerHidden]
					get
					{
						return <>2__current;
					}
				}

				object IEnumerator.Current
				{
					[DebuggerHidden]
					get
					{
						return <>2__current;
					}
				}

				[DebuggerHidden]
				public <EnforceKeyboardFontSizesCoroutine>d__82(int <>1__state)
				{
					this.<>1__state = <>1__state;
				}

				[DebuggerHidden]
				void IDisposable.Dispose()
				{
					<>1__state = -2;
				}

				private bool MoveNext()
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<i>5__1 = 0;
						break;
					case 1:
						<>1__state = -1;
						<i>5__1++;
						break;
					}
					if (<i>5__1 < 3)
					{
						<>4__this.ForceKeyboardFontSizes();
						<>2__current = null;
						<>1__state = 1;
						return true;
					}
					return false;
				}

				bool IEnumerator.MoveNext()
				{
					//ILSpy generated this explicit interface implementation from .override directive in MoveNext
					return this.MoveNext();
				}

				[DebuggerHidden]
				void IEnumerator.Reset()
				{
					throw new NotSupportedException();
				}
			}

			private readonly string _mainButtonLabel;

			private readonly List<(string name, Action<TabBuilder> configure)> _tabDescs;

			private readonly List<(string label, UnityAction action)> _fixedDescs;

			private Menu _activeMenu;

			private RuntimeTabMenu _tabMenu;

			private bool _contentBuilt;

			private bool _hasAttemptedInitialDump;

			private GameObject _mainButtonObj;

			private Button _mainButton;

			private Transform _mainMenuRoot;

			private CanvasGroup _mainMenuCG;

			private MenuItemList _mainMenuItemList;

			private GameObject _submenuObj;

			private CanvasGroup _submenuCG;

			private MenuItemList _submenuItemList;

			private readonly List<Button> _fixedButtonInstances = new List<Button>();

			private GameObject _kbRoot;

			private CanvasGroup _kbCG;

			private Button[][] _kbCharRows;

			private string[][] _kbLowerRows;

			private string[][] _kbUpperRows;

			private Button[] _kbSpecialRow;

			private readonly List<GameObject> _kbAllButtons = new List<GameObject>();

			private bool _kbShift;

			private bool _kbUseLowercaseFontForKeyLabels;

			private Button _kbShiftBtn;

			private InputFieldInfo _kbActiveField;

			private Button _kbReturnButton;

			private Action _kbOnDone;

			private bool _kbBuilt;

			private GameObject[] _savedSubmenuItems;

			private bool _kbHasEdited;

			private int _kbNavFrame = -1;

			private float _kbCursorTimer = 0f;

			private bool _kbCursorVisible = true;

			private InputFieldInfo _mouseTypingField;

			private bool _mouseTypingActive;

			private int _mouseTypingNavFrame = -1;

			private int _mouseCursorBlinkFrame = -1;

			private bool _mouseHasEdited;

			private float _mouseCursorTimer = 0f;

			private bool _mouseCursorVisible = true;

			private bool _kbUsingOverlay;

			private const float CanvasW = 860f;

			private const float CanvasH = 650f;

			private const float ContentH = 460f;

			private const float ContentPad = 10f;

			private readonly float _sideMargin;

			private readonly float _topMargin;

			private RectTransform _submenuRect;

			private string[] _currentTabNames;

			internal bool IsMouseTyping => _mouseTypingActive;

			internal bool KbVisible => (Object)(object)_kbCG != (Object)null && _kbCG.alpha > 0.5f;

			internal Transform GameCanvasTransform => ((Object)(object)_kbRoot != (Object)null && !_kbUsingOverlay) ? _kbRoot.transform.parent : null;

			internal Transform KbRootTransform
			{
				get
				{
					GameObject kbRoot = _kbRoot;
					return (kbRoot != null) ? kbRoot.transform : null;
				}
			}

			public bool IsKeyboardOpen => _kbActiveField != null;

			private bool IsKbButton(GameObject go)
			{
				return (Object)(object)go != (Object)null && _kbAllButtons.Contains(go);
			}

			internal InjectedMenu(MenuBuilder b)
			{
				_mainButtonLabel = b._mainButtonLabel;
				_tabDescs = b._tabs;
				_fixedDescs = b._fixed;
				_sideMargin = b._sideMargin;
				_topMargin = b._topMargin;
				_currentTabNames = new string[b._tabs.Count];
				for (int i = 0; i < b._tabs.Count; i++)
				{
					_currentTabNames[i] = b._tabs[i].name;
				}
			}

			public Button GetFixedButton(int index)
			{
				return (index >= 0 && index < _fixedButtonInstances.Count) ? _fixedButtonInstances[index] : null;
			}

			public Button GetTab(int index)
			{
				return (_tabMenu?.Tabs != null && index >= 0 && index < _tabMenu.Tabs.Length) ? _tabMenu.Tabs[index] : null;
			}

			public void SetMainButtonLabel(string label)
			{
				if (!((Object)(object)_mainButtonObj == (Object)null))
				{
					TMP_Text componentInChildren = _mainButtonObj.GetComponentInChildren<TMP_Text>(true);
					if (!((Object)(object)componentInChildren == (Object)null))
					{
						componentInChildren.text = label;
						componentInChildren.ForceMeshUpdate(false, false);
					}
				}
			}

			public void SetTabName(int index, string name)
			{
				if (index < 0)
				{
					return;
				}
				if (_currentTabNames != null && index < _currentTabNames.Length)
				{
					_currentTabNames[index] = name;
				}
				_tabMenu?.UpdateTabName(index, name);
				if (_tabMenu?.Tabs != null && index < _tabMenu.Tabs.Length)
				{
					Button val = _tabMenu.Tabs[index];
					if ((Object)(object)val != (Object)null)
					{
						SetButtonLabel(((Component)val).gameObject, name);
					}
				}
			}

			public void OnMenuAwake(Menu menu)
			{
				_activeMenu = menu;
				TryInject(menu, "Awake");
			}

			public void OnMenuPreUpdate(Menu menu)
			{
				//IL_058f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0595: Invalid comparison between Unknown and I4
				_activeMenu = menu;
				if ((Object)(object)menu == (Object)null)
				{
					return;
				}
				if ((Object)(object)_mainButtonObj == (Object)null || (Object)(object)_submenuObj == (Object)null)
				{
					TryInject(menu, "PreUpdateRetry");
				}
				bool submenuVisible = GetSubmenuVisible();
				bool kbVisible = KbVisible;
				bool flag = IsCapturingKeybindProvider?.Invoke() ?? false;
				bool flag2 = IsOverlayBlockingMenuProvider?.Invoke() ?? false;
				if (kbVisible)
				{
					HandleKeyboardInput(menu, flag, submenuVisible);
				}
				if (submenuVisible && !kbVisible && !flag)
				{
					if (_mouseTypingActive && _mouseTypingField != null && Time.frameCount != _mouseTypingNavFrame)
					{
						_mouseTypingNavFrame = Time.frameCount;
						bool flag3 = false;
						string inputString = Input.inputString;
						for (int i = 0; i < inputString.Length; i++)
						{
							char c = inputString[i];
							switch (c)
							{
							case '\b':
								if (_mouseTypingField.Value.Length > 0)
								{
									_mouseTypingField.Value = _mouseTypingField.Value.Substring(0, _mouseTypingField.Value.Length - 1);
									flag3 = true;
								}
								continue;
							default:
								if (c != '\n')
								{
									_mouseTypingField.Value += c;
									flag3 = true;
									continue;
								}
								break;
							case '\r':
								break;
							}
							_mouseTypingField.OnChanged?.Invoke(_mouseTypingField.Value);
							CloseMouseTyping(restoreSelection: false);
							flag3 = false;
							break;
						}
						if (Input.GetKeyDown((KeyCode)27) && _mouseTypingActive)
						{
							CloseMouseTyping();
							flag3 = false;
						}
						if (Input.GetMouseButtonDown(0) && _mouseTypingActive && (Object)(object)_mouseTypingField?.OwnerButton != (Object)null && !IsPointerOverGameObject(((Component)_mouseTypingField.OwnerButton).gameObject))
						{
							CloseMouseTyping(restoreSelection: false);
							flag3 = false;
						}
						if (flag3 && _mouseTypingField != null)
						{
							_mouseHasEdited = true;
							RefreshMouseTypingDisplay();
							_mouseTypingField.OnChanged?.Invoke(_mouseTypingField.Value);
						}
					}
					if (_mouseTypingActive && (Object)(object)_mouseTypingField?.DisplayText != (Object)null && Time.frameCount != _mouseCursorBlinkFrame)
					{
						_mouseCursorBlinkFrame = Time.frameCount;
						_mouseCursorTimer += Time.unscaledDeltaTime;
						if (_mouseCursorTimer >= 0.53f)
						{
							_mouseCursorTimer = 0f;
							_mouseCursorVisible = !_mouseCursorVisible;
							RefreshMouseTypingDisplay();
						}
					}
					if (!flag2)
					{
						TryHandleCancel(menu);
						if (_tabMenu != null && menu.rwPlayer != null)
						{
							if (menu.rwPlayer.GetButtonDown(18))
							{
								_tabMenu.SetActiveTab((_tabMenu.ActiveTab - 1 + _tabMenu.TabCount) % _tabMenu.TabCount);
							}
							else if (menu.rwPlayer.GetButtonDown(17))
							{
								_tabMenu.SetActiveTab((_tabMenu.ActiveTab + 1) % _tabMenu.TabCount);
							}
						}
					}
				}
				if (kbVisible)
				{
					if (submenuVisible && (Object)(object)_submenuItemList != (Object)null && !flag2)
					{
						MenuItemList.active = _submenuItemList;
					}
				}
				else if (submenuVisible && flag2)
				{
					GameObject[] overlayNavigableItems = OverlayNavigableItems;
					if ((Object)(object)_submenuItemList != (Object)null && overlayNavigableItems != null && overlayNavigableItems.Length != 0)
					{
						if (_savedSubmenuItems == null)
						{
							_savedSubmenuItems = Il2CppArrayBase<GameObject>.op_Implicit((Il2CppArrayBase<GameObject>)(object)_submenuItemList.items);
						}
						_submenuItemList.items = Il2CppReferenceArray<GameObject>.op_Implicit(overlayNavigableItems);
						MenuItemList.active = _submenuItemList;
					}
					else
					{
						MenuItemList.active = null;
					}
				}
				else if (submenuVisible && !flag2)
				{
					if ((Object)(object)_submenuItemList != (Object)null && _savedSubmenuItems != null)
					{
						_submenuItemList.items = Il2CppReferenceArray<GameObject>.op_Implicit(_savedSubmenuItems);
						_savedSubmenuItems = null;
					}
					if ((Object)(object)_submenuItemList != (Object)null)
					{
						MenuItemList.active = _submenuItemList;
					}
					if (_mouseTypingActive && (Object)(object)_mouseTypingField?.OwnerButton != (Object)null && (Object)(object)_submenuItemList != (Object)null)
					{
						_submenuItemList.items = Il2CppReferenceArray<GameObject>.op_Implicit((GameObject[])(object)new GameObject[1] { ((Component)_mouseTypingField.OwnerButton).gameObject });
					}
				}
				else if ((int)menu.currentMenuScreen == 0 && (Object)(object)_mainMenuItemList != (Object)null)
				{
					MenuItemList.active = _mainMenuItemList;
				}
			}

			private void HandleKeyboardInput(Menu menu, bool isCapturingKeybind, bool submenuVisible)
			{
				EventSystem current = EventSystem.current;
				GameObject val = ((current != null) ? current.currentSelectedGameObject : null);
				if (((Object)(object)val == (Object)null || !IsKbButton(val)) && _kbCharRows != null && _kbCharRows.Length != 0)
				{
					val = ((Component)_kbCharRows[0][0]).gameObject;
					if (current != null)
					{
						current.SetSelectedGameObject(val);
					}
				}
				if (!isCapturingKeybind && Time.frameCount != _kbNavFrame)
				{
					_kbNavFrame = Time.frameCount;
					if ((Object)(object)val != (Object)null && IsKbButton(val) && menu.rwPlayer != null)
					{
						float axis = menu.rwPlayer.GetAxis(12);
						float axisPrev = menu.rwPlayer.GetAxisPrev(12);
						float axis2 = menu.rwPlayer.GetAxis(13);
						float axisPrev2 = menu.rwPlayer.GetAxisPrev(13);
						Selectable component = val.GetComponent<Selectable>();
						Selectable val2 = null;
						if (axis2 < -0.5f && axisPrev2 >= -0.5f)
						{
							val2 = ((component != null) ? component.navigation.selectOnDown : null);
						}
						else if (axis2 > 0.5f && axisPrev2 <= 0.5f)
						{
							val2 = ((component != null) ? component.navigation.selectOnUp : null);
						}
						else if (axis > 0.5f && axisPrev <= 0.5f)
						{
							val2 = ((component != null) ? component.navigation.selectOnRight : null);
						}
						else if (axis < -0.5f && axisPrev >= -0.5f)
						{
							val2 = ((component != null) ? component.navigation.selectOnLeft : null);
						}
						if ((Object)(object)val2 != (Object)null)
						{
							if (current != null)
							{
								current.SetSelectedGameObject(((Component)val2).gameObject);
							}
							val = ((Component)val2).gameObject;
						}
						if (_kbUsingOverlay && (Input.GetKeyDown((KeyCode)330) || Input.GetKeyDown((KeyCode)331)))
						{
							Button val3 = ((val != null) ? val.GetComponent<Button>() : null);
							if (val3 != null)
							{
								((UnityEvent)val3.onClick).Invoke();
							}
						}
					}
					if (menu.rwPlayer != null && (Input.GetKeyDown((KeyCode)27) || Input.GetKeyDown((KeyCode)332) || menu.rwPlayer.GetButtonDown(15)))
					{
						CloseKeyboardOverlay((Object)(object)_kbReturnButton == (Object)null && _kbOnDone != null);
					}
					if ((Object)(object)_kbActiveField?.DisplayText != (Object)null)
					{
						_kbCursorTimer += Time.unscaledDeltaTime;
						if (_kbCursorTimer >= 0.53f)
						{
							_kbCursorTimer = 0f;
							_kbCursorVisible = !_kbCursorVisible;
							KbBlinkCursor();
						}
					}
				}
				if (submenuVisible && (Object)(object)_submenuItemList != (Object)null && (Object)(object)val != (Object)null)
				{
					_submenuItemList.items = Il2CppReferenceArray<GameObject>.op_Implicit((GameObject[])(object)new GameObject[1] { val });
				}
			}

			public void OnMenuUpdate(Menu menu)
			{
				_activeMenu = menu;
				if (!((Object)(object)menu == (Object)null))
				{
					if (Input.GetKeyDown((KeyCode)290))
					{
						Reset();
						TryInject(menu, "Reinject_F9");
					}
					if ((Object)(object)_mainButtonObj == (Object)null || (Object)(object)_submenuObj == (Object)null)
					{
						TryInject(menu, "UpdateRetry");
					}
					UpdateVisibility(menu);
					EnsureSelection();
				}
			}

			private void TryInject(Menu menu, string reason)
			{
				if ((Object)(object)menu == (Object)null)
				{
					return;
				}
				ResolveExisting(menu);
				if (!_hasAttemptedInitialDump)
				{
					_hasAttemptedInitialDump = true;
				}
				if ((Object)(object)menu.mainMenuCanvas == (Object)null)
				{
					return;
				}
				Button val = FindTemplateButton(menu);
				if (!((Object)(object)val == (Object)null))
				{
					_mainMenuRoot = ((Component)val).transform.parent;
					if ((Object)(object)_mainMenuRoot != (Object)null)
					{
						_mainMenuCG = ((Component)_mainMenuRoot).GetComponent<CanvasGroup>() ?? ((Component)_mainMenuRoot).gameObject.AddComponent<CanvasGroup>();
						_mainMenuItemList = ((Component)_mainMenuRoot).GetComponent<MenuItemList>();
					}
					if ((Object)(object)_mainButtonObj == (Object)null)
					{
						_mainButtonObj = BuildMainButton(menu, val);
					}
					if ((Object)(object)_submenuObj == (Object)null)
					{
						_submenuObj = BuildSubmenu(menu, val);
					}
					IntegrateIntoMainItemList();
					EnsureTabContent(menu, val);
					UpdateVisibility(menu);
				}
			}

			private void EnsureTabContent(Menu menu, Button tmpl)
			{
				if (_contentBuilt || (Object)(object)_submenuObj == (Object)null)
				{
					return;
				}
				Transform obj = _submenuObj.transform.Find("CustomSettingsContentRoot");
				RectTransform val = (RectTransform)(object)((obj is RectTransform) ? obj : null);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				Button nativeTabSource = null;
				Menu me = Menu.me;
				if ((Object)(object)((me != null) ? me.tabs : null) != (Object)null)
				{
					Transform transform = ((Component)Menu.me.tabs).transform;
					for (int i = 0; i < transform.childCount; i++)
					{
						Transform child = transform.GetChild(i);
						Button val2 = ((child != null) ? ((Component)child).GetComponent<Button>() : null);
						if ((Object)(object)val2 != (Object)null)
						{
							nativeTabSource = val2;
							break;
						}
					}
				}
				string[] array = new string[_tabDescs.Count];
				for (int j = 0; j < _tabDescs.Count; j++)
				{
					array[j] = ((_currentTabNames != null && j < _currentTabNames.Length) ? _currentTabNames[j] : _tabDescs[j].name);
				}
				_tabMenu = BuildNativeTabMenu(array, val, nativeTabSource, tmpl);
				_tabMenu.ManagedItemList = _submenuItemList;
				Selectable[] array2 = (Selectable[])(object)new Selectable[_fixedButtonInstances.Count];
				for (int k = 0; k < _fixedButtonInstances.Count; k++)
				{
					array2[k] = (Selectable)(object)_fixedButtonInstances[k];
				}
				_tabMenu.SetFixedMenuItems(array2);
				Toggle toggle = FindToggleTemplate(menu);
				Slider slider = FindSliderTemplate(menu);
				TabBuilder obj2 = new TabBuilder();
				_currentInjectedMenu = this;
				for (int l = 0; l < _tabDescs.Count; l++)
				{
					ConfigureTabPage(_tabMenu, l, tmpl, toggle, slider);
					_tabDescs[l].configure?.Invoke(obj2);
				}
				_currentInjectedMenu = null;
				BuildKeyboard(menu, tmpl);
				_tabMenu.SetActiveTab(0);
				_contentBuilt = true;
			}

			private GameObject BuildMainButton(Menu menu, Button tmpl)
			{
				//IL_006f: Unknown result type (might be due to invalid IL or missing references)
				//IL_007c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0089: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
				GameObject val = Object.Instantiate<GameObject>(((Component)tmpl).gameObject, ((Component)tmpl).transform.parent);
				((Object)val).name = "BBSMP_MainMenuButton";
				StripLocalizationComponents(val);
				val.transform.SetSiblingIndex(((Component)tmpl).transform.GetSiblingIndex() + 1);
				RectTransform component = val.GetComponent<RectTransform>();
				RectTransform component2 = ((Component)tmpl).GetComponent<RectTransform>();
				if ((Object)(object)component != (Object)null && (Object)(object)component2 != (Object)null)
				{
					component.anchorMin = component2.anchorMin;
					component.anchorMax = component2.anchorMax;
					component.pivot = component2.pivot;
					component.sizeDelta = component2.sizeDelta;
					((Transform)component).localScale = Vector3.one;
					float num = Mathf.Max(45f, Mathf.Abs(component2.sizeDelta.y) + 10f);
					component.anchoredPosition = component2.anchoredPosition + new Vector2(0f, num);
				}
				_mainButton = val.GetComponent<Button>();
				ClearButtonEvents(_mainButton);
				Button mainButton = _mainButton;
				if (mainButton != null)
				{
					((UnityEvent)mainButton.onClick).AddListener(UnityAction.op_Implicit((Action)delegate
					{
						SetSubmenuVisible(isVisible: true);
					}));
				}
				SetButtonLabel(val, _mainButtonLabel);
				return val;
			}

			private GameObject BuildSubmenu(Menu menu, Button tmpl)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Expected O, but got Unknown
				//IL_0042: Unknown result type (might be due to invalid IL or missing references)
				//IL_0058: Unknown result type (might be due to invalid IL or missing references)
				//IL_006e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0084: Unknown result type (might be due to invalid IL or missing references)
				//IL_009a: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e7: Expected O, but got Unknown
				//IL_010c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0122: Unknown result type (might be due to invalid IL or missing references)
				//IL_0138: Unknown result type (might be due to invalid IL or missing references)
				//IL_014e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0164: Unknown result type (might be due to invalid IL or missing references)
				//IL_018f: Unknown result type (might be due to invalid IL or missing references)
				//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
				//IL_028c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0299: Unknown result type (might be due to invalid IL or missing references)
				//IL_02a6: Unknown result type (might be due to invalid IL or missing references)
				//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
				//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
				GameObject val = new GameObject("BBSMP_SubmenuCanvas");
				val.transform.SetParent(menu.mainMenuCanvas.transform, false);
				val.transform.SetAsLastSibling();
				RectTransform val2 = val.AddComponent<RectTransform>();
				val2.anchorMin = new Vector2(0f, 1f);
				val2.anchorMax = new Vector2(0f, 1f);
				val2.pivot = new Vector2(0f, 1f);
				val2.sizeDelta = new Vector2(860f, 650f);
				val2.anchoredPosition = new Vector2(10f, -10f);
				_submenuCG = val.AddComponent<CanvasGroup>();
				_submenuCG.alpha = 0f;
				_submenuCG.blocksRaycasts = false;
				_submenuCG.interactable = false;
				GameObject val3 = new GameObject("CustomSettingsContentRoot");
				val3.transform.SetParent(val.transform, false);
				RectTransform val4 = val3.AddComponent<RectTransform>();
				val4.anchorMin = new Vector2(0f, 1f);
				val4.anchorMax = new Vector2(0f, 1f);
				val4.pivot = new Vector2(0f, 1f);
				val4.sizeDelta = new Vector2(800f, 460f);
				val4.anchoredPosition = new Vector2(10f, -10f);
				RectTransform component = ((Component)tmpl).GetComponent<RectTransform>();
				float num = (((Object)(object)component != (Object)null) ? Mathf.Max(200f, component.sizeDelta.x) : 520f);
				float num2 = (((Object)(object)component != (Object)null) ? Mathf.Clamp(component.sizeDelta.y, 40f, 72f) : 52f);
				_fixedButtonInstances.Clear();
				for (int num3 = _fixedDescs.Count - 1; num3 >= 0; num3--)
				{
					(string label, UnityAction action) tuple = _fixedDescs[num3];
					string item = tuple.label;
					UnityAction item2 = tuple.action;
					GameObject val5 = Object.Instantiate<GameObject>(((Component)tmpl).gameObject, val.transform);
					((Object)val5).name = $"BBSMP_Fixed_{num3}";
					StripLocalizationComponents(val5);
					Button component2 = val5.GetComponent<Button>();
					ClearButtonEvents(component2);
					SetButtonLabel(val5, item);
					RectTransform component3 = val5.GetComponent<RectTransform>();
					component3.anchorMin = Vector2.zero;
					component3.anchorMax = Vector2.zero;
					component3.pivot = Vector2.zero;
					component3.sizeDelta = new Vector2(num, num2);
					int num4 = _fixedDescs.Count - 1 - num3;
					component3.anchoredPosition = new Vector2(10f, 10f + (float)num4 * (num2 + 10f));
					UnityAction capturedAction = item2;
					if (component2 != null)
					{
						((UnityEvent)component2.onClick).AddListener(UnityAction.op_Implicit((Action)delegate
						{
							UnityAction obj = capturedAction;
							if (obj != null)
							{
								obj.Invoke();
							}
							SetSubmenuVisible(isVisible: false);
						}));
					}
					_fixedButtonInstances.Insert(0, component2);
				}
				_submenuItemList = val.AddComponent<MenuItemList>();
				_submenuItemList.items = Il2CppReferenceArray<GameObject>.op_Implicit((GameObject[])(object)new GameObject[0]);
				_submenuRect = val2;
				ApplyMargin();
				return val;
			}

			private void BuildKeyboard(Menu menu, Button tmpl, bool useLowercaseFontForLetterKeys = true)
			{
				//IL_037c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0386: Expected O, but got Unknown
				//IL_03cd: Unknown result type (might be due to invalid IL or missing references)
				//IL_03e4: Unknown result type (might be due to invalid IL or missing references)
				//IL_03fb: Unknown result type (might be due to invalid IL or missing references)
				//IL_040e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0425: Unknown result type (might be due to invalid IL or missing references)
				//IL_0453: Unknown result type (might be due to invalid IL or missing references)
				//IL_05f7: Unknown result type (might be due to invalid IL or missing references)
				//IL_060e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0625: Unknown result type (might be due to invalid IL or missing references)
				//IL_0639: Unknown result type (might be due to invalid IL or missing references)
				//IL_0657: Unknown result type (might be due to invalid IL or missing references)
				//IL_0877: Unknown result type (might be due to invalid IL or missing references)
				//IL_088e: Unknown result type (might be due to invalid IL or missing references)
				//IL_08a5: Unknown result type (might be due to invalid IL or missing references)
				//IL_08bc: Unknown result type (might be due to invalid IL or missing references)
				//IL_08cd: Unknown result type (might be due to invalid IL or missing references)
				if (_kbBuilt || (Object)(object)((menu != null) ? menu.mainMenuCanvas : null) == (Object)null || (Object)(object)tmpl == (Object)null)
				{
					return;
				}
				_kbUseLowercaseFontForKeyLabels = useLowercaseFontForLetterKeys;
				_kbLowerRows = new string[4][]
				{
					new string[11]
					{
						"1", "2", "3", "4", "5", "6", "7", "8", "9", "0",
						"."
					},
					new string[10] { "q", "w", "e", "r", "t", "y", "u", "i", "o", "p" },
					new string[9] { "a", "s", "d", "f", "g", "h", "j", "k", "l" },
					new string[7] { "z", "x", "c", "v", "b", "n", "m" }
				};
				_kbUpperRows = new string[4][]
				{
					new string[11]
					{
						"1", "2", "3", "4", "5", "6", "7", "8", "9", "0",
						"."
					},
					new string[10] { "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P" },
					new string[9] { "A", "S", "D", "F", "G", "H", "J", "K", "L" },
					new string[7] { "Z", "X", "C", "V", "B", "N", "M" }
				};
				int num = _kbLowerRows.Length + 1;
				float num2 = 20f + (float)num * 44f + (float)(num - 1) * 4f - 15f;
				float num3 = 780f;
				int num4 = 0;
				for (int i = 0; i < _kbLowerRows.Length; i++)
				{
					if (_kbLowerRows[i].Length > num4)
					{
						num4 = _kbLowerRows[i].Length;
					}
				}
				float num5 = (num3 - (float)(num4 - 1) * 6f) / (float)num4;
				_kbRoot = new GameObject("BBSMP_Keyboard");
				_kbRoot.transform.SetParent(menu.mainMenuCanvas.transform, false);
				_kbRoot.transform.SetAsLastSibling();
				RectTransform val = _kbRoot.AddComponent<RectTransform>();
				val.anchorMin = new Vector2(0.5f, 0f);
				val.anchorMax = new Vector2(0.5f, 0f);
				val.pivot = new Vector2(0.5f, 0f);
				val.sizeDelta = new Vector2(800f, num2);
				val.anchoredPosition = new Vector2(0f, 100f);
				Image val2 = _kbRoot.AddComponent<Image>();
				((Graphic)val2).color = new Color(0.05f, 0.11f, 0.18f, 0.97f);
				_kbCG = _kbRoot.AddComponent<CanvasGroup>();
				_kbCG.alpha = 0f;
				_kbCG.interactable = false;
				_kbCG.blocksRaycasts = false;
				_kbCharRows = new Button[_kbLowerRows.Length][];
				float num6 = -10f;
				for (int j = 0; j < _kbLowerRows.Length; j++)
				{
					int num7 = _kbLowerRows[j].Length;
					float num8 = num5;
					float num9 = (float)num7 * num8 + (float)(num7 - 1) * 6f;
					float num10 = (0f - num9) * 0.5f;
					_kbCharRows[j] = (Button[])(object)new Button[num7];
					for (int k = 0; k < num7; k++)
					{
						int capturedRow = j;
						int capturedCol = k;
						GameObject val3 = Object.Instantiate<GameObject>(((Component)tmpl).gameObject, _kbRoot.transform);
						((Object)val3).name = "BBSMP_Key_" + _kbUpperRows[j][k];
						StripLocalizationComponents(val3);
						Button component = val3.GetComponent<Button>();
						ClearButtonEvents(component);
						if ((Object)(object)component != (Object)null)
						{
							((UnityEvent)component.onClick).AddListener(UnityAction.op_Implicit((Action)delegate
							{
								KbType(capturedRow, capturedCol);
							}));
						}
						SetButtonLabel(val3, _kbLowerRows[j][k], _kbUseLowercaseFontForKeyLabels);
						TMP_Text componentInChildren = val3.GetComponentInChildren<TMP_Text>(true);
						if ((Object)(object)componentInChildren != (Object)null)
						{
							componentInChildren.fontSize = 20f;
						}
						RectTransform component2 = val3.GetComponent<RectTransform>();
						component2.anchorMin = new Vector2(0.5f, 1f);
						component2.anchorMax = new Vector2(0.5f, 1f);
						component2.pivot = new Vector2(0f, 1f);
						component2.sizeDelta = new Vector2(num8, 44f);
						component2.anchoredPosition = new Vector2(num10 + (float)k * (num8 + 6f), num6);
						_kbCharRows[j][k] = component;
						_kbAllButtons.Add(val3);
					}
					num6 -= 48f;
				}
				float num11 = num3 - 216f - 18f;
				float[] obj = new float[4] { 72f, 0f, 72f, 72f };
				obj[1] = num11;
				float[] array = obj;
				string[] array2 = new string[4] { "Shift", "Space", "Back", "Done" };
				_kbSpecialRow = (Button[])(object)new Button[4];
				float num12 = (0f - num3) * 0.5f;
				for (int l = 0; l < 4; l++)
				{
					GameObject val4 = Object.Instantiate<GameObject>(((Component)tmpl).gameObject, _kbRoot.transform);
					((Object)val4).name = "BBSMP_Key_" + array2[l];
					StripLocalizationComponentsImmediate(val4);
					Button component3 = val4.GetComponent<Button>();
					ClearButtonEvents(component3);
					if ((Object)(object)component3 != (Object)null)
					{
						switch (l)
						{
						case 0:
							((UnityEvent)component3.onClick).AddListener(UnityAction.op_Implicit((Action)KbToggleShift));
							_kbShiftBtn = component3;
							break;
						case 1:
							((UnityEvent)component3.onClick).AddListener(UnityAction.op_Implicit((Action)KbSpace));
							break;
						case 2:
							((UnityEvent)component3.onClick).AddListener(UnityAction.op_Implicit((Action)KbBackspace));
							break;
						case 3:
							((UnityEvent)component3.onClick).AddListener(UnityAction.op_Implicit((Action)KbDone));
							break;
						}
					}
					SetButtonLabel(val4, array2[l]);
					TMP_Text componentInChildren2 = val4.GetComponentInChildren<TMP_Text>(true);
					if ((Object)(object)componentInChildren2 != (Object)null)
					{
						componentInChildren2.fontSize = 20f;
					}
					RectTransform component4 = val4.GetComponent<RectTransform>();
					component4.anchorMin = new Vector2(0.5f, 1f);
					component4.anchorMax = new Vector2(0.5f, 1f);
					component4.pivot = new Vector2(0f, 1f);
					component4.sizeDelta = new Vector2(array[l], 44f);
					component4.anchoredPosition = new Vector2(num12, num6);
					num12 += array[l] + 6f;
					_kbSpecialRow[l] = component3;
					_kbAllButtons.Add(val4);
				}
				WireKeyboardNavigation();
				ForceKeyboardFontSizes();
				MelonCoroutines.Start(EnforceKeyboardFontSizesCoroutine());
				_kbBuilt = true;
			}

			private void WireKeyboardNavigation()
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				//IL_002c: Expected O, but got Unknown
				//IL_0171: Unknown result type (might be due to invalid IL or missing references)
				//IL_0176: Unknown result type (might be due to invalid IL or missing references)
				//IL_0180: Expected O, but got Unknown
				for (int i = 0; i < _kbCharRows.Length; i++)
				{
					int num = _kbCharRows[i].Length;
					for (int j = 0; j < num; j++)
					{
						Navigation val = new Navigation
						{
							mode = (Mode)0
						};
						val.selectOnLeft = (Selectable)(object)((j > 0) ? _kbCharRows[i][j - 1] : null);
						val.selectOnRight = (Selectable)(object)((j < num - 1) ? _kbCharRows[i][j + 1] : null);
						val.selectOnUp = (Selectable)(object)((i > 0) ? _kbCharRows[i - 1][Mathf.Min(j, _kbCharRows[i - 1].Length - 1)] : null);
						if (i < _kbCharRows.Length - 1)
						{
							val.selectOnDown = (Selectable)(object)_kbCharRows[i + 1][Mathf.Min(j, _kbCharRows[i + 1].Length - 1)];
						}
						else
						{
							int num2 = Mathf.Clamp(j * _kbSpecialRow.Length / _kbCharRows[i].Length, 0, _kbSpecialRow.Length - 1);
							val.selectOnDown = (Selectable)(object)_kbSpecialRow[num2];
						}
						((Selectable)_kbCharRows[i][j]).navigation = val;
					}
				}
				int num3 = _kbCharRows.Length - 1;
				int num4 = _kbCharRows[num3].Length;
				for (int k = 0; k < _kbSpecialRow.Length; k++)
				{
					Navigation val2 = new Navigation
					{
						mode = (Mode)0
					};
					val2.selectOnLeft = (Selectable)(object)((k > 0) ? _kbSpecialRow[k - 1] : null);
					val2.selectOnRight = (Selectable)(object)((k < _kbSpecialRow.Length - 1) ? _kbSpecialRow[k + 1] : null);
					val2.selectOnDown = null;
					int num5 = Mathf.Clamp(k * num4 / _kbSpecialRow.Length, 0, num4 - 1);
					val2.selectOnUp = (Selectable)(object)_kbCharRows[num3][num5];
					((Selectable)_kbSpecialRow[k]).navigation = val2;
				}
			}

			private void KbType(int row, int col)
			{
				if (_kbActiveField != null)
				{
					string[][] array = (_kbShift ? _kbUpperRows : _kbLowerRows);
					_kbActiveField.Value += array[row][col];
					_kbHasEdited = true;
					KbRefreshDisplay();
					_kbActiveField.OnChanged?.Invoke(_kbActiveField.Value);
					if (_kbShift)
					{
						_kbShift = false;
						KbRefreshKeyLabels();
					}
				}
			}

			private void KbSpace()
			{
				if (_kbActiveField != null)
				{
					_kbActiveField.Value += " ";
					_kbHasEdited = true;
					KbRefreshDisplay();
					_kbActiveField.OnChanged?.Invoke(_kbActiveField.Value);
				}
			}

			private void KbBackspace()
			{
				if (_kbActiveField != null && _kbActiveField.Value.Length != 0)
				{
					_kbActiveField.Value = _kbActiveField.Value.Substring(0, _kbActiveField.Value.Length - 1);
					_kbHasEdited = true;
					KbRefreshDisplay();
					_kbActiveField.OnChanged?.Invoke(_kbActiveField.Value);
				}
			}

			private void KbToggleShift()
			{
				_kbShift = !_kbShift;
				KbRefreshKeyLabels();
			}

			private void KbRefreshKeyLabels()
			{
				if (_kbCharRows == null)
				{
					return;
				}
				string[][] array = (_kbShift ? _kbUpperRows : _kbLowerRows);
				for (int i = 0; i < _kbCharRows.Length; i++)
				{
					for (int j = 0; j < _kbCharRows[i].Length; j++)
					{
						SetButtonLabel(((Component)_kbCharRows[i][j]).gameObject, array[i][j], _kbUseLowercaseFontForKeyLabels);
					}
				}
				if ((Object)(object)_kbShiftBtn != (Object)null)
				{
					SetButtonLabel(((Component)_kbShiftBtn).gameObject, _kbShift ? "SHIFT" : "Shift");
					ForceKeyboardFontSize(((Component)_kbShiftBtn).gameObject);
				}
			}

			private void ForceKeyboardFontSizes()
			{
				if (_kbAllButtons.Count != 0)
				{
					for (int i = 0; i < _kbAllButtons.Count; i++)
					{
						ForceKeyboardFontSize(_kbAllButtons[i]);
					}
				}
			}

			private static void ForceKeyboardFontSize(GameObject keyObj)
			{
				if (!((Object)(object)keyObj == (Object)null))
				{
					TMP_Text componentInChildren = keyObj.GetComponentInChildren<TMP_Text>(true);
					if (!((Object)(object)componentInChildren == (Object)null))
					{
						componentInChildren.fontSize = 20f;
						componentInChildren.ForceMeshUpdate(false, false);
					}
				}
			}

			[IteratorStateMachine(typeof(<EnforceKeyboardFontSizesCoroutine>d__82))]
			private IEnumerator EnforceKeyboardFontSizesCoroutine()
			{
				//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
				return new <EnforceKeyboardFontSizesCoroutine>d__82(0)
				{
					<>4__this = this
				};
			}

			private void KbRefreshDisplay()
			{
				//IL_008c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0091: Unknown result type (might be due to invalid IL or missing references)
				//IL_0115: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
				InputFieldInfo kbActiveField = _kbActiveField;
				if (kbActiveField != null && !((Object)(object)kbActiveField.DisplayText == (Object)null))
				{
					TMP_Text displayText = kbActiveField.DisplayText;
					_kbCursorVisible = true;
					_kbCursorTimer = 0f;
					ApplyCaretText(kbActiveField, _kbCursorVisible, _kbHasEdited);
					displayText.ForceMeshUpdate(false, false);
					float num = 0f;
					RectTransform rectTransform = displayText.rectTransform;
					if ((Object)(object)rectTransform != (Object)null && (Object)(object)kbActiveField.Viewport != (Object)null)
					{
						Rect rect = kbActiveField.Viewport.rect;
						float width = ((Rect)(ref rect)).width;
						float displayWidthForRenderedText = GetDisplayWidthForRenderedText(displayText, displayText.text);
						num = ((width > 1f) ? Mathf.Max(0f, displayWidthForRenderedText - width) : 0f);
						rectTransform.offsetMin = new Vector2(0f - num, rectTransform.offsetMin.y);
						rectTransform.offsetMax = new Vector2(0f - num, rectTransform.offsetMax.y);
					}
					if ((Object)(object)kbActiveField.CursorImage != (Object)null)
					{
						((Graphic)kbActiveField.CursorImage).color = Color.clear;
					}
				}
			}

			private void KbBlinkCursor()
			{
				//IL_0072: Unknown result type (might be due to invalid IL or missing references)
				//IL_0077: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00da: Unknown result type (might be due to invalid IL or missing references)
				InputFieldInfo kbActiveField = _kbActiveField;
				if (!((Object)(object)kbActiveField?.DisplayText == (Object)null))
				{
					TMP_Text displayText = kbActiveField.DisplayText;
					ApplyCaretText(kbActiveField, _kbCursorVisible, _kbHasEdited);
					displayText.ForceMeshUpdate(false, false);
					RectTransform rectTransform = displayText.rectTransform;
					if ((Object)(object)rectTransform != (Object)null && (Object)(object)kbActiveField.Viewport != (Object)null)
					{
						Rect rect = kbActiveField.Viewport.rect;
						float width = ((Rect)(ref rect)).width;
						float displayWidthForRenderedText = GetDisplayWidthForRenderedText(displayText, displayText.text);
						float num = ((width > 1f) ? Mathf.Max(0f, displayWidthForRenderedText - width) : 0f);
						rectTransform.offsetMin = new Vector2(0f - num, rectTransform.offsetMin.y);
						rectTransform.offsetMax = new Vector2(0f - num, rectTransform.offsetMax.y);
					}
				}
			}

			internal void OpenKeyboard(InputFieldInfo info, Button returnButton)
			{
				OpenKeyboard(info, returnButton, null, useOverlay: false);
			}

			internal void OpenKeyboard(InputFieldInfo info, Button returnButton, Action onDone)
			{
				OpenKeyboard(info, returnButton, onDone, useOverlay: false);
			}

			public void OpenKeyboardForChat(InputFieldInfo info, Action onDone)
			{
				OpenKeyboard(info, null, onDone, useOverlay: true);
			}

			private void OpenKeyboard(InputFieldInfo info, Button returnButton, Action onDone, bool useOverlay)
			{
				if (_kbBuilt)
				{
					_kbActiveField = info;
					_kbReturnButton = returnButton;
					_kbOnDone = onDone;
					_kbUsingOverlay = useOverlay;
					_kbShift = false;
					_kbHasEdited = false;
					_kbCursorVisible = true;
					_kbCursorTimer = 0f;
					if (useOverlay && (Object)(object)_kbRoot != (Object)null)
					{
						RectTransform val = EnsureKeyboardOverlayRoot();
						_kbRoot.transform.SetParent((Transform)(object)val, false);
						_kbRoot.transform.SetAsLastSibling();
						ShowKeyboardOverlay();
					}
					KbRefreshKeyLabels();
					KbRefreshDisplay();
					SetKeyboardVisible(visible: true);
				}
			}

			internal void CloseKeyboardForChat()
			{
				CloseKeyboard();
			}

			public void CloseKeyboardOverlay()
			{
				CloseKeyboardOverlay(fireChatCancelledEvent: false);
			}

			public void CloseKeyboardOverlay(bool fireChatCancelledEvent)
			{
				CloseKeyboard();
				HideKeyboardOverlay();
				if (fireChatCancelledEvent)
				{
					MenuInjectionLibrary.OnChatKeyboardCancelled?.Invoke();
				}
			}

			private void CloseKeyboard()
			{
				//IL_0088: Unknown result type (might be due to invalid IL or missing references)
				//IL_0060: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00df: Unknown result type (might be due to invalid IL or missing references)
				//IL_010d: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)_kbActiveField?.DisplayText != (Object)null)
				{
					TMP_Text displayText = _kbActiveField.DisplayText;
					if (_kbActiveField.Value.Length > 0)
					{
						displayText.text = _kbActiveField.Value;
						((Graphic)displayText).color = _kbActiveField.ActiveColor;
					}
					else
					{
						displayText.text = _kbActiveField.Placeholder;
						((Graphic)displayText).color = _kbActiveField.PlaceholderColor;
					}
					displayText.ForceMeshUpdate(false, false);
					RectTransform rectTransform = displayText.rectTransform;
					if ((Object)(object)rectTransform != (Object)null)
					{
						rectTransform.offsetMin = new Vector2(0f, rectTransform.offsetMin.y);
						rectTransform.offsetMax = new Vector2(0f, rectTransform.offsetMax.y);
					}
					if ((Object)(object)_kbActiveField.CursorImage != (Object)null)
					{
						((Graphic)_kbActiveField.CursorImage).color = Color.clear;
					}
				}
				SetKeyboardVisible(visible: false);
				_tabMenu?.SetActiveTab(_tabMenu.ActiveTab);
				Button kbReturnButton = _kbReturnButton;
				_kbActiveField = null;
				_kbReturnButton = null;
				_kbOnDone = null;
				if ((Object)(object)kbReturnButton != (Object)null)
				{
					EventSystem current = EventSystem.current;
					if (current != null)
					{
						current.SetSelectedGameObject(((Component)kbReturnButton).gameObject);
					}
				}
			}

			private void KbDone()
			{
				_kbOnDone?.Invoke();
				CloseKeyboard();
			}

			internal void OnInputFieldButtonClick(InputFieldInfo info, Button btn)
			{
				if (!IsMouseTyping)
				{
					if (Input.GetMouseButtonUp(0))
					{
						OpenMouseTyping(info);
					}
					else
					{
						OpenKeyboard(info, btn);
					}
				}
			}

			internal void OpenMouseTyping(InputFieldInfo info)
			{
				//IL_0052: Unknown result type (might be due to invalid IL or missing references)
				_mouseTypingField = info;
				_mouseTypingActive = true;
				_mouseTypingNavFrame = -1;
				_mouseCursorBlinkFrame = -1;
				_mouseHasEdited = false;
				_mouseCursorTimer = 0f;
				_mouseCursorVisible = true;
				if ((Object)(object)info?.CursorImage != (Object)null)
				{
					((Graphic)info.CursorImage).color = Color.clear;
				}
				EventSystem current = EventSystem.current;
				if (current != null)
				{
					current.SetSelectedGameObject((GameObject)null);
				}
				RefreshMouseTypingDisplay();
			}

			internal void ForceCloseMouseTypingInternal()
			{
				if (_mouseTypingActive)
				{
					CloseMouseTyping(restoreSelection: false);
				}
			}

			private void CloseMouseTyping(bool restoreSelection = true)
			{
				//IL_0066: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
				//IL_0108: Unknown result type (might be due to invalid IL or missing references)
				//IL_0112: Unknown result type (might be due to invalid IL or missing references)
				//IL_0124: Unknown result type (might be due to invalid IL or missing references)
				//IL_012e: Unknown result type (might be due to invalid IL or missing references)
				_mouseTypingActive = false;
				InputFieldInfo mouseTypingField = _mouseTypingField;
				_mouseTypingField = null;
				if (restoreSelection && (Object)(object)mouseTypingField?.OwnerButton != (Object)null)
				{
					EventSystem current = EventSystem.current;
					if (current != null)
					{
						current.SetSelectedGameObject(((Component)mouseTypingField.OwnerButton).gameObject);
					}
				}
				if ((Object)(object)mouseTypingField.CursorImage != (Object)null)
				{
					((Graphic)mouseTypingField.CursorImage).color = Color.clear;
				}
				if (!((Object)(object)mouseTypingField?.DisplayText == (Object)null))
				{
					TMP_Text displayText = mouseTypingField.DisplayText;
					if (mouseTypingField.Value.Length > 0)
					{
						displayText.text = mouseTypingField.Value;
						((Graphic)displayText).color = mouseTypingField.ActiveColor;
					}
					else
					{
						displayText.text = mouseTypingField.Placeholder;
						((Graphic)displayText).color = mouseTypingField.PlaceholderColor;
					}
					displayText.ForceMeshUpdate(false, false);
					RectTransform rectTransform = displayText.rectTransform;
					if ((Object)(object)rectTransform != (Object)null)
					{
						rectTransform.offsetMin = new Vector2(0f, rectTransform.offsetMin.y);
						rectTransform.offsetMax = new Vector2(0f, rectTransform.offsetMax.y);
					}
				}
			}

			private void RefreshMouseTypingDisplay()
			{
				//IL_007a: Unknown result type (might be due to invalid IL or missing references)
				//IL_007f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0103: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00df: Unknown result type (might be due to invalid IL or missing references)
				InputFieldInfo mouseTypingField = _mouseTypingField;
				if (!((Object)(object)mouseTypingField?.DisplayText == (Object)null))
				{
					TMP_Text displayText = mouseTypingField.DisplayText;
					ApplyCaretText(mouseTypingField, _mouseCursorVisible, _mouseHasEdited);
					displayText.ForceMeshUpdate(false, false);
					float num = 0f;
					RectTransform rectTransform = displayText.rectTransform;
					if ((Object)(object)rectTransform != (Object)null && (Object)(object)mouseTypingField.Viewport != (Object)null)
					{
						Rect rect = mouseTypingField.Viewport.rect;
						float width = ((Rect)(ref rect)).width;
						float displayWidthForRenderedText = GetDisplayWidthForRenderedText(displayText, displayText.text);
						num = ((width > 1f) ? Mathf.Max(0f, displayWidthForRenderedText - width) : 0f);
						rectTransform.offsetMin = new Vector2(0f - num, rectTransform.offsetMin.y);
						rectTransform.offsetMax = new Vector2(0f - num, rectTransform.offsetMax.y);
					}
					if ((Object)(object)mouseTypingField.CursorImage != (Object)null)
					{
						((Graphic)mouseTypingField.CursorImage).color = Color.clear;
					}
				}
			}

			private static void ApplyCaretText(InputFieldInfo field, bool showCaret, bool hasEdited)
			{
				//IL_003d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Unknown result type (might be due to invalid IL or missing references)
				if (!((Object)(object)field?.DisplayText == (Object)null))
				{
					bool flag = !string.IsNullOrEmpty(field.Value);
					((Graphic)field.DisplayText).color = (flag ? field.ActiveColor : field.PlaceholderColor);
					if (!flag)
					{
						field.DisplayText.text = (showCaret ? "|" : "<color=#FFFFFF00>|</color>");
					}
					else
					{
						field.DisplayText.text = (showCaret ? (field.Value + "|") : (field.Value + "<color=#FFFFFF00>|</color>"));
					}
				}
			}

			private static float GetDisplayWidthForRenderedText(TMP_Text text, string renderedText)
			{
				//IL_0034: Unknown result type (might be due to invalid IL or missing references)
				//IL_0045: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)text == (Object)null)
				{
					return 0f;
				}
				if (string.IsNullOrEmpty(renderedText))
				{
					return 0f;
				}
				float x = text.GetPreferredValues(renderedText + "M").x;
				float x2 = text.GetPreferredValues("M").x;
				return Mathf.Max(0f, x - x2);
			}

			private static bool IsPointerOverGameObject(GameObject target)
			{
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				//IL_002c: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_003e: Expected O, but got Unknown
				EventSystem current = EventSystem.current;
				if ((Object)(object)current == (Object)null || (Object)(object)target == (Object)null)
				{
					return false;
				}
				PointerEventData val = new PointerEventData(current)
				{
					position = Vector2.op_Implicit(Input.mousePosition)
				};
				List<RaycastResult> val2 = new List<RaycastResult>();
				current.RaycastAll(val, val2);
				for (int i = 0; i < val2.Count; i++)
				{
					GameObject gameObject = val2[i].gameObject;
					if (!((Object)(object)gameObject == (Object)null) && ((Object)(object)gameObject == (Object)(object)target || gameObject.transform.IsChildOf(target.transform)))
					{
						return true;
					}
				}
				return false;
			}

			private void SetKeyboardVisible(bool visible)
			{
				if ((Object)(object)_kbCG == (Object)null)
				{
					return;
				}
				_kbCG.alpha = (visible ? 1f : 0f);
				_kbCG.interactable = visible;
				_kbCG.blocksRaycasts = visible;
				if (visible && _kbCharRows != null && _kbCharRows.Length != 0)
				{
					Button val = _kbCharRows[0][0];
					if ((Object)(object)_submenuItemList != (Object)null)
					{
						_submenuItemList.items = Il2CppReferenceArray<GameObject>.op_Implicit((GameObject[])(object)new GameObject[1] { ((Component)val).gameObject });
					}
					EventSystem current = EventSystem.current;
					if (current != null)
					{
						current.SetSelectedGameObject(((Component)val).gameObject);
					}
					MenuItemList.active = _submenuItemList;
				}
			}

			private void IntegrateIntoMainItemList()
			{
				if ((Object)(object)_mainMenuItemList == (Object)null || (Object)(object)_mainButtonObj == (Object)null)
				{
					return;
				}
				Il2CppReferenceArray<GameObject> items = _mainMenuItemList.items;
				if (items == null || ((Il2CppArrayBase<GameObject>)(object)items).Length == 0)
				{
					return;
				}
				for (int i = 0; i < ((Il2CppArrayBase<GameObject>)(object)items).Length; i++)
				{
					if ((Object)(object)((Il2CppArrayBase<GameObject>)(object)items)[i] == (Object)(object)_mainButtonObj)
					{
						return;
					}
				}
				Menu activeMenu = _activeMenu;
				Button val = ((activeMenu != null) ? activeMenu.ContinueGameButton : null);
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				int num = -1;
				for (int j = 0; j < ((Il2CppArrayBase<GameObject>)(object)items).Length; j++)
				{
					if ((Object)(object)((Il2CppArrayBase<GameObject>)(object)items)[j] == (Object)(object)((Component)val).gameObject)
					{
						num = j;
						break;
					}
				}
				if (num < 0)
				{
					return;
				}
				GameObject[] array = (GameObject[])(object)new GameObject[((Il2CppArrayBase<GameObject>)(object)items).Length + 1];
				int k = 0;
				int num2 = 0;
				for (; k < array.Length; k++)
				{
					if (k == num + 1)
					{
						array[k] = _mainButtonObj;
					}
					else
					{
						array[k] = ((Il2CppArrayBase<GameObject>)(object)items)[num2++];
					}
				}
				_mainMenuItemList.items = Il2CppReferenceArray<GameObject>.op_Implicit(array);
			}

			private void UpdateVisibility(Menu menu)
			{
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0033: Invalid comparison between Unknown and I4
				if ((Object)(object)menu == (Object)null)
				{
					return;
				}
				bool flag = (Object)(object)menu.mainMenuCanvas != (Object)null && menu.mainMenuCanvas.activeInHierarchy && (int)menu.currentMenuScreen == 0;
				if ((Object)(object)_mainButtonObj != (Object)null)
				{
					_mainButtonObj.SetActive(flag);
				}
				if (!flag)
				{
					if (GetSubmenuVisible())
					{
						SetSubmenuVisible(isVisible: false);
					}
					return;
				}
				bool submenuVisible = GetSubmenuVisible();
				if ((Object)(object)_mainMenuCG != (Object)null)
				{
					_mainMenuCG.alpha = (submenuVisible ? 0f : 1f);
					_mainMenuCG.blocksRaycasts = !submenuVisible;
					_mainMenuCG.interactable = !submenuVisible;
				}
				if ((Object)(object)menu.titleGroup != (Object)null)
				{
					menu.titleGroup.alpha = (submenuVisible ? 0f : 1f);
				}
			}

			private void SetSubmenuVisible(bool isVisible)
			{
				if ((Object)(object)_submenuCG == (Object)null)
				{
					return;
				}
				bool flag = _submenuCG.alpha > 0.5f;
				if (flag == isVisible)
				{
					return;
				}
				if (!isVisible && KbVisible)
				{
					SetKeyboardVisible(visible: false);
				}
				_submenuCG.alpha = (isVisible ? 1f : 0f);
				_submenuCG.blocksRaycasts = isVisible;
				_submenuCG.interactable = isVisible;
				for (int i = 0; i < _fixedButtonInstances.Count; i++)
				{
					if ((Object)(object)_fixedButtonInstances[i] != (Object)null)
					{
						((Selectable)_fixedButtonInstances[i]).interactable = isVisible;
					}
				}
				if ((Object)(object)_mainButton != (Object)null)
				{
					((Selectable)_mainButton).interactable = !isVisible;
				}
				if (isVisible)
				{
					ApplyMargin();
					_tabMenu?.OnShown();
					if ((Object)(object)_submenuItemList != (Object)null)
					{
						MenuItemList.active = _submenuItemList;
					}
				}
				else if ((Object)(object)_mainMenuItemList != (Object)null)
				{
					MenuItemList.active = _mainMenuItemList;
				}
				EventSystem current = EventSystem.current;
				if ((Object)(object)current != (Object)null)
				{
					if (isVisible && _fixedButtonInstances.Count > 0 && (Object)(object)_fixedButtonInstances[0] != (Object)null)
					{
						current.SetSelectedGameObject(((Component)_fixedButtonInstances[0]).gameObject);
					}
					else if (!isVisible && (Object)(object)_mainButton != (Object)null)
					{
						current.SetSelectedGameObject(((Component)_mainButton).gameObject);
					}
				}
				UpdateVisibility(_activeMenu);
			}

			private void EnsureSelection()
			{
				if (KbVisible || _mouseTypingActive)
				{
					return;
				}
				EventSystem current = EventSystem.current;
				if ((Object)(object)current == (Object)null)
				{
					return;
				}
				GameObject currentSelectedGameObject = current.currentSelectedGameObject;
				if (!((Object)(object)currentSelectedGameObject == (Object)null) && currentSelectedGameObject.activeInHierarchy)
				{
					Selectable component = currentSelectedGameObject.GetComponent<Selectable>();
					if (component == null || component.interactable)
					{
						return;
					}
				}
				if (GetSubmenuVisible())
				{
					if (_fixedButtonInstances.Count > 0 && (Object)(object)_fixedButtonInstances[0] != (Object)null)
					{
						current.SetSelectedGameObject(((Component)_fixedButtonInstances[0]).gameObject);
					}
					return;
				}
				Menu activeMenu = _activeMenu;
				if ((Object)(object)((activeMenu != null) ? activeMenu.ContinueGameButton : null) != (Object)null)
				{
					current.SetSelectedGameObject(((Component)_activeMenu.ContinueGameButton).gameObject);
				}
			}

			private void TryHandleCancel(Menu menu)
			{
				if (((menu != null) ? menu.rwPlayer : null) != null && !KbVisible && !_mouseTypingActive && (Input.GetKeyDown((KeyCode)27) || menu.rwPlayer.GetButtonDown(15)))
				{
					SetSubmenuVisible(isVisible: false);
				}
			}

			private void ApplyMargin()
			{
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)_submenuRect != (Object)null)
				{
					_submenuRect.anchoredPosition = new Vector2(10f + _sideMargin, -10f - _topMargin);
				}
			}

			private bool GetSubmenuVisible()
			{
				return (Object)(object)_submenuCG != (Object)null && _submenuCG.alpha > 0.5f;
			}

			private void ResolveExisting(Menu menu)
			{
				if ((Object)(object)((menu != null) ? menu.mainMenuCanvas : null) == (Object)null)
				{
					return;
				}
				Il2CppArrayBase<Transform> componentsInChildren = menu.mainMenuCanvas.GetComponentsInChildren<Transform>(true);
				List<GameObject> list = new List<GameObject>();
				List<GameObject> list2 = new List<GameObject>();
				List<GameObject> list3 = new List<GameObject>();
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					Transform val = componentsInChildren[i];
					if (!((Object)(object)val == (Object)null))
					{
						if (((Object)val).name == "BBSMP_MainMenuButton")
						{
							list.Add(((Component)val).gameObject);
						}
						else if (((Object)val).name == "BBSMP_SubmenuCanvas")
						{
							list2.Add(((Component)val).gameObject);
						}
						else if (((Object)val).name == "BBSMP_Keyboard")
						{
							list3.Add(((Component)val).gameObject);
						}
					}
				}
				if (list3.Count > 0)
				{
					if (_kbBuilt)
					{
						_kbRoot = list3[0];
						GameObject kbRoot = _kbRoot;
						_kbCG = ((kbRoot != null) ? kbRoot.GetComponent<CanvasGroup>() : null);
					}
					else
					{
						for (int j = 0; j < list3.Count; j++)
						{
							Object.Destroy((Object)(object)list3[j]);
						}
						_kbRoot = null;
						_kbCG = null;
					}
					for (int k = 1; k < list3.Count; k++)
					{
						Object.Destroy((Object)(object)list3[k]);
					}
				}
				if (list.Count > 0)
				{
					_mainButtonObj = list[0];
					_mainButton = _mainButtonObj.GetComponent<Button>();
					for (int l = 1; l < list.Count; l++)
					{
						Object.Destroy((Object)(object)list[l]);
					}
					_mainMenuRoot = _mainButtonObj.transform.parent;
					Transform mainMenuRoot = _mainMenuRoot;
					object obj = ((mainMenuRoot != null) ? ((Component)mainMenuRoot).GetComponent<CanvasGroup>() : null);
					if (obj == null)
					{
						Transform mainMenuRoot2 = _mainMenuRoot;
						obj = ((mainMenuRoot2 != null) ? ((Component)mainMenuRoot2).gameObject.AddComponent<CanvasGroup>() : null);
					}
					_mainMenuCG = (CanvasGroup)obj;
					Transform mainMenuRoot3 = _mainMenuRoot;
					_mainMenuItemList = ((mainMenuRoot3 != null) ? ((Component)mainMenuRoot3).GetComponent<MenuItemList>() : null);
				}
				if (list2.Count > 0)
				{
					_submenuObj = list2[0];
					_submenuCG = _submenuObj.GetComponent<CanvasGroup>();
					_submenuItemList = _submenuObj.GetComponent<MenuItemList>();
					for (int m = 1; m < list2.Count; m++)
					{
						Object.Destroy((Object)(object)list2[m]);
					}
					_fixedButtonInstances.Clear();
					for (int n = 0; n < _fixedDescs.Count; n++)
					{
						Transform val2 = _submenuObj.transform.Find($"BBSMP_Fixed_{n}");
						_fixedButtonInstances.Add((val2 != null) ? ((Component)val2).GetComponent<Button>() : null);
					}
				}
			}

			private void Reset()
			{
				if ((Object)(object)_mainButtonObj != (Object)null)
				{
					Object.Destroy((Object)(object)_mainButtonObj);
				}
				if ((Object)(object)_submenuObj != (Object)null)
				{
					Object.Destroy((Object)(object)_submenuObj);
				}
				if ((Object)(object)_kbRoot != (Object)null)
				{
					Object.Destroy((Object)(object)_kbRoot);
				}
				_mainButtonObj = null;
				_mainButton = null;
				_submenuObj = null;
				_submenuCG = null;
				_submenuItemList = null;
				_submenuRect = null;
				_mainMenuRoot = null;
				_mainMenuCG = null;
				_mainMenuItemList = null;
				_tabMenu = null;
				_contentBuilt = false;
				_fixedButtonInstances.Clear();
				_kbRoot = null;
				_kbCG = null;
				_kbCharRows = null;
				_kbSpecialRow = null;
				_kbLowerRows = null;
				_kbUpperRows = null;
				_kbAllButtons.Clear();
				_kbActiveField = null;
				_kbReturnButton = null;
				_kbBuilt = false;
				_kbShift = false;
				_kbShiftBtn = null;
				_kbNavFrame = -1;
				_kbCursorTimer = 0f;
				_kbCursorVisible = true;
			}

			private static Button FindTemplateButton(Menu menu)
			{
				if ((Object)(object)menu.ContinueGameButton != (Object)null)
				{
					return menu.ContinueGameButton;
				}
				if ((Object)(object)menu.mainMenuCanvas == (Object)null)
				{
					return null;
				}
				Il2CppArrayBase<Button> componentsInChildren = menu.mainMenuCanvas.GetComponentsInChildren<Button>(true);
				if (componentsInChildren == null || componentsInChildren.Length == 0)
				{
					return null;
				}
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					if (!((Object)(object)componentsInChildren[i] == (Object)null))
					{
						TMP_Text componentInChildren = ((Component)componentsInChildren[i]).GetComponentInChildren<TMP_Text>(true);
						string text = ((componentInChildren != null) ? componentInChildren.text : null) ?? "";
						if (text.Contains("continue", StringComparison.OrdinalIgnoreCase))
						{
							return componentsInChildren[i];
						}
					}
				}
				return componentsInChildren[0];
			}

			private static Toggle FindToggleTemplate(Menu menu)
			{
				if ((Object)(object)((menu != null) ? menu.mainMenuCanvas : null) == (Object)null)
				{
					return null;
				}
				Il2CppArrayBase<Toggle> componentsInChildren = menu.mainMenuCanvas.GetComponentsInChildren<Toggle>(true);
				if (componentsInChildren == null || componentsInChildren.Length == 0)
				{
					return null;
				}
				Toggle val = componentsInChildren[0];
				if ((Object)(object)val != (Object)null)
				{
					StripLocalizationComponentsImmediate(((Component)val).gameObject);
				}
				return val;
			}

			private static Slider FindSliderTemplate(Menu menu)
			{
				if ((Object)(object)((menu != null) ? menu.mainMenuCanvas : null) == (Object)null)
				{
					return null;
				}
				Il2CppArrayBase<Slider> componentsInChildren = menu.mainMenuCanvas.GetComponentsInChildren<Slider>(true);
				return (componentsInChildren != null && componentsInChildren.Length > 0) ? componentsInChildren[0] : null;
			}

			private static void DumpHierarchy(Menu menu, string reason)
			{
				//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
				try
				{
					if (!((Object)(object)menu == (Object)null))
					{
						StringBuilder stringBuilder = new StringBuilder();
						stringBuilder.AppendLine("=== BabyStepsMenuLib Hierarchy Dump ===");
						StringBuilder stringBuilder2 = stringBuilder;
						StringBuilder stringBuilder3 = stringBuilder2;
						StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(8, 1, stringBuilder2);
						handler.AppendLiteral("Reason: ");
						handler.AppendFormatted(reason);
						stringBuilder3.AppendLine(ref handler);
						stringBuilder2 = stringBuilder;
						StringBuilder stringBuilder4 = stringBuilder2;
						handler = new StringBuilder.AppendInterpolatedStringHandler(6, 1, stringBuilder2);
						handler.AppendLiteral("Time: ");
						handler.AppendFormatted(DateTime.Now, "O");
						stringBuilder4.AppendLine(ref handler);
						stringBuilder2 = stringBuilder;
						StringBuilder stringBuilder5 = stringBuilder2;
						handler = new StringBuilder.AppendInterpolatedStringHandler(18, 2, stringBuilder2);
						handler.AppendLiteral("Screen: ");
						handler.AppendFormatted<MenuScreen>(menu.currentMenuScreen);
						handler.AppendLiteral("  Paused: ");
						handler.AppendFormatted(menu.paused);
						stringBuilder5.AppendLine(ref handler);
						if ((Object)(object)menu.mainMenuCanvas != (Object)null)
						{
							stringBuilder2 = stringBuilder;
							StringBuilder stringBuilder6 = stringBuilder2;
							handler = new StringBuilder.AppendInterpolatedStringHandler(9, 1, stringBuilder2);
							handler.AppendLiteral("CanvasW: ");
							handler.AppendFormatted(GetPath(menu.mainMenuCanvas.transform));
							stringBuilder6.AppendLine(ref handler);
							AppendTransform(stringBuilder, menu.mainMenuCanvas.transform, 0, 6);
						}
						string text = Path.Combine(Environment.CurrentDirectory, "UserData");
						Directory.CreateDirectory(text);
						File.WriteAllText(Path.Combine(text, "BabyStepsMenuLib_MenuHierarchyDump.txt"), stringBuilder.ToString());
					}
				}
				catch (Exception value)
				{
					Instance logger = Logger;
					if (logger != null)
					{
						logger.Error($"[MenuInject] Dump failed: {value}");
					}
				}
			}

			private static void AppendTransform(StringBuilder sb, Transform root, int depth, int maxDepth)
			{
				if ((Object)(object)root == (Object)null || depth > maxDepth)
				{
					return;
				}
				string value = new string(' ', depth * 2);
				Il2CppArrayBase<Component> components = ((Component)root).GetComponents<Component>();
				List<string> list = new List<string>();
				for (int i = 0; i < components.Length; i++)
				{
					if ((Object)(object)components[i] != (Object)null)
					{
						list.Add(((object)components[i]).GetType().Name);
					}
				}
				StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(5, 3, sb);
				handler.AppendFormatted(value);
				handler.AppendLiteral("- ");
				handler.AppendFormatted(((Object)root).name);
				handler.AppendLiteral(" [");
				handler.AppendFormatted(string.Join(", ", list));
				handler.AppendLiteral("]");
				sb.AppendLine(ref handler);
				for (int j = 0; j < root.childCount; j++)
				{
					AppendTransform(sb, root.GetChild(j), depth + 1, maxDepth);
				}
			}

			private static string GetPath(Transform t)
			{
				if ((Object)(object)t == (Object)null)
				{
					return "<null>";
				}
				Stack<string> stack = new Stack<string>();
				while ((Object)(object)t != (Object)null)
				{
					stack.Push(((Object)t).name);
					t = t.parent;
				}
				return string.Join("/", stack);
			}
		}

		internal static readonly List<InjectedMenu> _registeredMenus = new List<InjectedMenu>();

		private static RectTransform customRoot;

		private static Button buttonTemplate;

		private static Toggle toggleTemplate;

		private static Slider sliderTemplate;

		private const float SliderHandleSize = 112f;

		private static Sprite _inputFieldSprite;

		private static Sprite _sliderHandleSprite;

		private static Sprite _solidSprite;

		private static TMP_FontAsset _lowercaseTextFont;

		private const float KeyboardKeyFontSize = 20f;

		private static RectTransform _keyboardOverlayRoot;

		private static CanvasGroup _keyboardOverlayCanvasGroup;

		private static Image _popupDimImage;

		private static Canvas _popupDimCanvas;

		private static RuntimeTabMenu _currentTabMenu;

		private static int _currentTabPage = -1;

		private static InjectedMenu _currentInjectedMenu;

		private static float nextY;

		private const float Spacing = 10f;

		private const float DefaultHeight = 52f;

		internal static readonly Color TabUnselected = new Color(0.435f, 0.676f, 0.726f, 1f);

		internal static readonly Color TabSelected = new Color(1f, 1f, 1f, 0.78f);

		internal static readonly Color TabText = new Color(0f, 0.169f, 0.283f, 1f);

		internal static readonly Color TabHighlighted = new Color(0.519f, 0.804f, 0.865f, 1f);

		public static Instance Logger { get; set; }

		public static Func<bool> IsCapturingKeybindProvider { get; set; }

		public static Func<bool> IsOverlayBlockingMenuProvider { get; set; }

		public static GameObject[] OverlayNavigableItems { get; set; }

		public static bool IsAnyKeyboardVisible => _registeredMenus.Exists((InjectedMenu m) => m.KbVisible);

		internal static InjectedMenu CurrentMenu => _currentInjectedMenu;

		public static InputFieldInfo LastCreatedInputFieldInfo { get; private set; }

		public static event Action OnChatKeyboardCancelled;

		public static InjectedMenu GetKeyboardMenu()
		{
			if (_registeredMenus.Count > 0)
			{
				return _registeredMenus[0];
			}
			return null;
		}

		private static RectTransform EnsureKeyboardOverlayRoot()
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_keyboardOverlayRoot != (Object)null)
			{
				return _keyboardOverlayRoot;
			}
			Il2CppReferenceArray<Type> val = new Il2CppReferenceArray<Type>(5L);
			((Il2CppArrayBase<Type>)(object)val)[0] = Il2CppType.Of<RectTransform>();
			((Il2CppArrayBase<Type>)(object)val)[1] = Il2CppType.Of<Canvas>();
			((Il2CppArrayBase<Type>)(object)val)[2] = Il2CppType.Of<CanvasScaler>();
			((Il2CppArrayBase<Type>)(object)val)[3] = Il2CppType.Of<GraphicRaycaster>();
			((Il2CppArrayBase<Type>)(object)val)[4] = Il2CppType.Of<CanvasGroup>();
			GameObject val2 = new GameObject("BBSMP_ChatKeyboardOverlay", val);
			Object.DontDestroyOnLoad((Object)(object)val2);
			Canvas component = val2.GetComponent<Canvas>();
			component.renderMode = (RenderMode)0;
			component.overrideSorting = true;
			component.sortingOrder = 10000;
			_keyboardOverlayCanvasGroup = val2.GetComponent<CanvasGroup>();
			_keyboardOverlayCanvasGroup.alpha = 1f;
			_keyboardOverlayCanvasGroup.blocksRaycasts = true;
			_keyboardOverlayCanvasGroup.interactable = true;
			_keyboardOverlayRoot = val2.GetComponent<RectTransform>();
			_keyboardOverlayRoot.anchorMin = Vector2.zero;
			_keyboardOverlayRoot.anchorMax = Vector2.one;
			_keyboardOverlayRoot.offsetMin = Vector2.zero;
			_keyboardOverlayRoot.offsetMax = Vector2.zero;
			return _keyboardOverlayRoot;
		}

		public static void ShowPopupDim(Color color)
		{
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Expected O, but got Unknown
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			if ((Object)(object)_popupDimImage == (Object)null)
			{
				Transform val = ((_registeredMenus.Count > 0) ? _registeredMenus[0] : null)?.GameCanvasTransform;
				if ((Object)(object)val == (Object)null)
				{
					GameObject val2 = new GameObject("BBSMP_PopupDimCanvas");
					Object.DontDestroyOnLoad((Object)(object)val2);
					_popupDimCanvas = val2.AddComponent<Canvas>();
					_popupDimCanvas.renderMode = (RenderMode)0;
					_popupDimCanvas.sortingOrder = 9998;
					val2.AddComponent<CanvasScaler>();
					val2.AddComponent<GraphicRaycaster>();
					val = val2.transform;
				}
				GameObject val3 = new GameObject("BBSMP_PopupDim");
				val3.transform.SetParent(val, false);
				RectTransform val4 = val3.AddComponent<RectTransform>();
				val4.anchorMin = Vector2.zero;
				val4.anchorMax = Vector2.one;
				Vector2 offsetMin = (val4.offsetMax = Vector2.zero);
				val4.offsetMin = offsetMin;
				_popupDimImage = val3.AddComponent<Image>();
				((Graphic)_popupDimImage).raycastTarget = true;
			}
			if ((Object)(object)_popupDimImage != (Object)null)
			{
				((Graphic)_popupDimImage).color = color;
				((Component)_popupDimImage).gameObject.SetActive(true);
				Canvas popupDimCanvas = _popupDimCanvas;
				if (popupDimCanvas != null)
				{
					((Component)popupDimCanvas).gameObject.SetActive(true);
				}
			}
			InjectedMenu injectedMenu = ((_registeredMenus.Count > 0) ? _registeredMenus[0] : null);
			Transform val5 = injectedMenu?.GameCanvasTransform;
			Transform val6 = injectedMenu?.KbRootTransform;
			if ((Object)(object)val5 != (Object)null && (Object)(object)val6 != (Object)null && (Object)(object)_popupDimImage != (Object)null && (Object)(object)((Component)_popupDimImage).transform.parent == (Object)(object)val5)
			{
				((Component)_popupDimImage).transform.SetAsLastSibling();
				val6.SetAsLastSibling();
			}
		}

		public static void HidePopupDim()
		{
			if ((Object)(object)_popupDimImage != (Object)null)
			{
				((Component)_popupDimImage).gameObject.SetActive(false);
			}
			if ((Object)(object)_popupDimCanvas != (Object)null)
			{
				((Component)_popupDimCanvas).gameObject.SetActive(false);
			}
		}

		internal static void HideKeyboardOverlay()
		{
			if ((Object)(object)_keyboardOverlayCanvasGroup != (Object)null)
			{
				_keyboardOverlayCanvasGroup.alpha = 0f;
				_keyboardOverlayCanvasGroup.blocksRaycasts = false;
				_keyboardOverlayCanvasGroup.interactable = false;
			}
		}

		internal static void ShowKeyboardOverlay()
		{
			RectTransform val = EnsureKeyboardOverlayRoot();
			if ((Object)(object)val != (Object)null)
			{
				CanvasGroup keyboardOverlayCanvasGroup = _keyboardOverlayCanvasGroup;
				if ((Object)(object)keyboardOverlayCanvasGroup != (Object)null)
				{
					keyboardOverlayCanvasGroup.alpha = 1f;
					keyboardOverlayCanvasGroup.blocksRaycasts = true;
					keyboardOverlayCanvasGroup.interactable = true;
				}
			}
		}

		private static TMP_FontAsset GetOrCreateLowercaseTextFont()
		{
			if ((Object)(object)_lowercaseTextFont != (Object)null)
			{
				return _lowercaseTextFont;
			}
			Font builtinResource = Resources.GetBuiltinResource<Font>("Arial.ttf");
			if ((Object)(object)builtinResource == (Object)null)
			{
				return null;
			}
			_lowercaseTextFont = TMP_FontAsset.CreateFontAsset(builtinResource);
			return _lowercaseTextFont;
		}

		private static void ApplyLowercaseTextFont(TMP_Text text)
		{
			if (!((Object)(object)text == (Object)null))
			{
				TMP_FontAsset orCreateLowercaseTextFont = GetOrCreateLowercaseTextFont();
				if ((Object)(object)orCreateLowercaseTextFont != (Object)null)
				{
					text.font = orCreateLowercaseTextFont;
				}
			}
		}

		private static Sprite GetOrCreateSliderHandleSprite()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_sliderHandleSprite != (Object)null)
			{
				return _sliderHandleSprite;
			}
			Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false);
			((Texture)val).filterMode = (FilterMode)1;
			Color32[] array = (Color32[])(object)new Color32[4096];
			float num = 31.5f;
			float num2 = 31.5f;
			float num3 = 26f;
			for (int i = 0; i < 64; i++)
			{
				for (int j = 0; j < 64; j++)
				{
					float num4 = (float)j - num;
					float num5 = (float)i - num2;
					float num6 = Mathf.Sqrt(num4 * num4 + num5 * num5);
					byte b = (byte)(Mathf.Clamp01(num3 + 0.5f - num6) * 255f);
					array[i * 64 + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, b);
				}
			}
			val.SetPixels32(Il2CppStructArray<Color32>.op_Implicit(array));
			val.Apply(false, false);
			_sliderHandleSprite = Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0);
			return _sliderHandleSprite;
		}

		private static Sprite GetOrCreateInputFieldSprite()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_inputFieldSprite != (Object)null)
			{
				return _inputFieldSprite;
			}
			Texture2D val = new Texture2D(128, 64, (TextureFormat)4, false);
			((Texture)val).filterMode = (FilterMode)1;
			float num = 18f;
			float num2 = 109f;
			float num3 = 18f;
			float num4 = 45f;
			Color32[] array = (Color32[])(object)new Color32[8192];
			for (int i = 0; i < 64; i++)
			{
				for (int j = 0; j < 128; j++)
				{
					float num5 = (((float)j < num) ? (num - (float)j) : (((float)j > num2) ? ((float)j - num2) : 0f));
					float num6 = (((float)i < num3) ? (num3 - (float)i) : (((float)i > num4) ? ((float)i - num4) : 0f));
					float num7 = Mathf.Sqrt(num5 * num5 + num6 * num6);
					byte b = (byte)(Mathf.Clamp01(18.5f - num7) * 255f);
					array[i * 128 + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, b);
				}
			}
			val.SetPixels32(Il2CppStructArray<Color32>.op_Implicit(array));
			val.Apply(false, false);
			_inputFieldSprite = Sprite.Create(val, new Rect(0f, 0f, 128f, 64f), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0, new Vector4(18f, 18f, 18f, 18f));
			return _inputFieldSprite;
		}

		private static Sprite GetOrCreateSolidSprite()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Expected O, but got Unknown
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_solidSprite != (Object)null)
			{
				return _solidSprite;
			}
			Texture2D val = new Texture2D(1, 1, (TextureFormat)4, false);
			val.SetPixels32(Il2CppStructArray<Color32>.op_Implicit((Color32[])(object)new Color32[1]
			{
				new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue)
			}));
			val.Apply(false, false);
			_solidSprite = Sprite.Create(val, new Rect(0f, 0f, 1f, 1f), new Vector2(0.5f, 0.5f));
			return _solidSprite;
		}

		public static void ForceCloseMouseTyping()
		{
			foreach (InjectedMenu registeredMenu in _registeredMenus)
			{
				registeredMenu.ForceCloseMouseTypingInternal();
			}
		}

		public static MenuBuilder CreateMenu(string mainButtonLabel)
		{
			return new MenuBuilder(mainButtonLabel);
		}

		public static TMP_FontAsset GetCurrentToggleFont()
		{
			Toggle obj = toggleTemplate;
			object obj2;
			if (obj == null)
			{
				obj2 = null;
			}
			else
			{
				Transform obj3 = ((Component)obj).transform.Find("Label");
				obj2 = ((obj3 != null) ? ((Component)obj3).GetComponent<TMP_Text>() : null);
			}
			TMP_Text val = (TMP_Text)obj2;
			return (val != null) ? val.font : null;
		}

		public static void Configure(RectTransform root, Button button, Toggle toggle = null, Slider slider = null)
		{
			customRoot = root;
			buttonTemplate = button;
			toggleTemplate = toggle;
			sliderTemplate = slider;
			_currentTabMenu = null;
			_currentTabPage = -1;
			ResetLayout();
		}

		public static void ConfigureTabPage(RuntimeTabMenu tabMenu, int pageIndex, Button button, Toggle toggle = null, Slider slider = null)
		{
			Configure(tabMenu?.GetPage(pageIndex), button, toggle, slider);
			_currentTabMenu = tabMenu;
			_currentTabPage = pageIndex;
		}

		public static RectTransform GetCustomRoot()
		{
			return customRoot;
		}

		public static void ClearCustomContent()
		{
			if ((Object)(object)customRoot == (Object)null)
			{
				return;
			}
			for (int num = ((Transform)customRoot).childCount - 1; num >= 0; num--)
			{
				Transform child = ((Transform)customRoot).GetChild(num);
				if ((Object)(object)child != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)child).gameObject);
				}
			}
			ResetLayout();
		}

		public static TMP_Text AddLabel(string text, RectTransform parent = null)
		{
			RectTransform val = parent ?? customRoot;
			if ((Object)(object)val == (Object)null || (Object)(object)buttonTemplate == (Object)null)
			{
				return null;
			}
			GameObject val2 = Object.Instantiate<GameObject>(((Component)buttonTemplate).gameObject, (Transform)(object)val);
			((Object)val2).name = "BBSMP_Label";
			StripLocalizationComponents(val2);
			Button component = val2.GetComponent<Button>();
			if ((Object)(object)component != (Object)null)
			{
				Object.Destroy((Object)(object)component);
			}
			Image component2 = val2.GetComponent<Image>();
			if ((Object)(object)component2 != (Object)null)
			{
				((Behaviour)component2).enabled = false;
			}
			TMP_Text componentInChildren = val2.GetComponentInChildren<TMP_Text>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.text = text;
				componentInChildren.alignment = (TextAlignmentOptions)4097;
				componentInChildren.ForceMeshUpdate(false, false);
			}
			PlaceInLayout(val2.GetComponent<RectTransform>(), val, 52f);
			return componentInChildren;
		}

		public static Image AddImage(Color color, float height = 52f, RectTransform parent = null)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = parent ?? customRoot;
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			GameObject val2 = new GameObject("BBSMP_Image");
			val2.transform.SetParent((Transform)(object)val, false);
			RectTransform rect = val2.AddComponent<RectTransform>();
			Image val3 = val2.AddComponent<Image>();
			val3.sprite = GetOrCreateSolidSprite();
			val3.type = (Type)0;
			((Graphic)val3).color = color;
			PlaceInLayout(rect, val, height);
			return val3;
		}

		public static Button AddButton(string text, UnityAction onClick, RectTransform parent = null)
		{
			RectTransform val = parent ?? customRoot;
			if ((Object)(object)val == (Object)null || (Object)(object)buttonTemplate == (Object)null)
			{
				return null;
			}
			GameObject val2 = Object.Instantiate<GameObject>(((Component)buttonTemplate).gameObject, (Transform)(object)val);
			((Object)val2).name = "BBSMP_Button";
			StripLocalizationComponents(val2);
			Button component = val2.GetComponent<Button>();
			ClearButtonEvents(component);
			if ((Object)(object)component != (Object)null && (Delegate)(object)onClick != (Delegate)null)
			{
				((UnityEvent)component.onClick).AddListener(onClick);
			}
			SetButtonLabel(val2, text);
			PlaceInLayout(val2.GetComponent<RectTransform>(), val, 52f);
			_currentTabMenu?.RegisterPageSelectable(_currentTabPage, (Selectable)(object)component);
			return component;
		}

		public static Toggle AddToggle(string text, bool initialValue, UnityAction<bool> onValueChanged, RectTransform parent = null)
		{
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Expected O, but got Unknown
			RectTransform val = parent ?? customRoot;
			if ((Object)(object)val == (Object)null || (Object)(object)toggleTemplate == (Object)null)
			{
				return null;
			}
			GameObject val2 = Object.Instantiate<GameObject>(((Component)toggleTemplate).gameObject, (Transform)(object)val);
			((Object)val2).name = "BBSMP_Toggle";
			Transform val3 = val2.transform.Find("Label");
			if ((Object)(object)val3 != (Object)null)
			{
				BBLocalize component = ((Component)val3).GetComponent<BBLocalize>();
				if ((Object)(object)component != (Object)null)
				{
					Object.DestroyImmediate((Object)(object)component);
				}
				TMP_Text component2 = ((Component)val3).GetComponent<TMP_Text>();
				if ((Object)(object)component2 != (Object)null)
				{
					component2.text = text;
				}
			}
			Toggle component3 = val2.GetComponent<Toggle>();
			if ((Object)(object)component3 == (Object)null)
			{
				return null;
			}
			component3.onValueChanged = new ToggleEvent();
			component3.isOn = initialValue;
			if ((Delegate)(object)onValueChanged != (Delegate)null)
			{
				((UnityEvent<bool>)(object)component3.onValueChanged).AddListener(onValueChanged);
			}
			PlaceInLayout(val2.GetComponent<RectTransform>(), val, 52f);
			_currentTabMenu?.RegisterPageSelectable(_currentTabPage, (Selectable)(object)component3);
			return component3;
		}

		public static Slider AddSlider(string text, float min, float max, float value, UnityAction<float> onValueChanged, bool wholeNumbers = false, RectTransform parent = null)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Expected O, but got Unknown
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0302: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = parent ?? customRoot;
			if ((Object)(object)val == (Object)null || (Object)(object)sliderTemplate == (Object)null)
			{
				return null;
			}
			Il2CppReferenceArray<Type> val2 = new Il2CppReferenceArray<Type>(2L);
			((Il2CppArrayBase<Type>)(object)val2)[0] = Il2CppType.Of<RectTransform>();
			((Il2CppArrayBase<Type>)(object)val2)[1] = Il2CppType.Of<HorizontalLayoutGroup>();
			GameObject val3 = new GameObject("BBSMP_SliderContainer", val2);
			RectTransform component = val3.GetComponent<RectTransform>();
			((Transform)component).SetParent((Transform)(object)val, false);
			HorizontalLayoutGroup component2 = val3.GetComponent<HorizontalLayoutGroup>();
			((LayoutGroup)component2).childAlignment = (TextAnchor)3;
			((HorizontalOrVerticalLayoutGroup)component2).spacing = 30f;
			((HorizontalOrVerticalLayoutGroup)component2).childForceExpandWidth = false;
			((HorizontalOrVerticalLayoutGroup)component2).childControlWidth = true;
			if (!string.IsNullOrEmpty(text))
			{
				TMP_Text val4 = AddLabel(text, component);
				if ((Object)(object)val4 != (Object)null)
				{
					LayoutElement val5 = ((Component)val4).GetComponent<LayoutElement>() ?? ((Component)val4).gameObject.AddComponent<LayoutElement>();
					val5.flexibleWidth = 0f;
					val4.ForceMeshUpdate(false, false);
				}
			}
			GameObject val6 = InstantiateSliderTemplateSafely(((Component)sliderTemplate).gameObject, (Transform)(object)component);
			((Object)val6).name = "BBSMP_Slider";
			StripLocalizationComponents(val6);
			Slider component3 = val6.GetComponent<Slider>();
			if ((Object)(object)component3 == (Object)null)
			{
				return null;
			}
			component3.onValueChanged = new SliderEvent();
			component3.minValue = min;
			component3.maxValue = max;
			component3.wholeNumbers = wholeNumbers;
			component3.SetValueWithoutNotify(Mathf.Clamp(value, min, max));
			if ((Delegate)(object)onValueChanged != (Delegate)null)
			{
				((UnityEvent<float>)(object)component3.onValueChanged).AddListener(onValueChanged);
			}
			LayoutElement val7 = val6.GetComponent<LayoutElement>() ?? val6.AddComponent<LayoutElement>();
			val7.flexibleWidth = 1f;
			val7.minWidth = 100f;
			RectTransform val8 = component3.handleRect;
			if ((Object)(object)val8 == (Object)null)
			{
				Il2CppArrayBase<RectTransform> componentsInChildren = val6.GetComponentsInChildren<RectTransform>(true);
				for (int i = 0; i < componentsInChildren.Length; i++)
				{
					RectTransform val9 = componentsInChildren[i];
					if (!((Object)(object)val9 == (Object)null))
					{
						string name = ((Object)((Component)val9).gameObject).name;
						if (name.IndexOf("Handle", StringComparison.OrdinalIgnoreCase) >= 0 && name.IndexOf("Area", StringComparison.OrdinalIgnoreCase) < 0 && name.IndexOf("Slide", StringComparison.OrdinalIgnoreCase) < 0)
						{
							val8 = val9;
							break;
						}
					}
				}
			}
			if ((Object)(object)val8 != (Object)null)
			{
				Image component4 = ((Component)val8).GetComponent<Image>();
				component3.handleRect = val8;
				val8.anchorMin = new Vector2(0.5f, 0.5f);
				val8.anchorMax = new Vector2(0.5f, 0.5f);
				val8.pivot = new Vector2(0.5f, 0.5f);
				((Transform)val8).localScale = Vector3.one;

Mods/BabyStepsMultiplayerClient.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Numerics;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using BabyStepsMenuLib;
using BabyStepsMultiplayerClient;
using BabyStepsMultiplayerClient.Audio;
using BabyStepsMultiplayerClient.Components;
using BabyStepsMultiplayerClient.Config;
using BabyStepsMultiplayerClient.Extensions;
using BabyStepsMultiplayerClient.Localization;
using BabyStepsMultiplayerClient.Networking;
using BabyStepsMultiplayerClient.Networking.Steam;
using BabyStepsMultiplayerClient.Player;
using BabyStepsMultiplayerClient.UI;
using BabyStepsMultiplayerClient.UI.Elements;
using BabyStepsNetworking.Client;
using BabyStepsNetworking.Host;
using BabyStepsNetworking.Packets;
using BabyStepsNetworking.ServerBrowser;
using BabyStepsNetworking.Shared;
using BabyStepsNetworking.Transport;
using BabyStepsNetworking.Transport.LiteNetLib;
using BabyStepsNetworking.Transport.LocalLoopback;
using BabyStepsNetworking.Transport.Steam;
using Concentus.Enums;
using Concentus.Structs;
using HarmonyLib;
using Il2Cpp;
using Il2CppBabySteps.Core.Audio;
using Il2CppCinemachine;
using Il2CppFMOD;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppNWH.DWP2.WaterObjects;
using Il2CppRewired;
using Il2CppSteamworks;
using Il2CppSystem;
using Il2CppSystem.Collections;
using Il2CppTMPro;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using Steamworks;
using Steamworks.Data;
using Tomlet;
using Tomlet.Models;
using Unity.LiveCapture.ARKitFaceCapture;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(Core), "BabyStepsMultiplayerClient", "1.3.2", "Caleb Orchard", "https://github.com/caleborchard/Baby-Steps-Multiplayer-Mod-Client")]
[assembly: MelonGame("DefaultCompany", "BabySteps")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("Caleb Orchard")]
[assembly: AssemblyConfiguration("Retail - Debug")]
[assembly: AssemblyDescription("A MelonLoader mod for Baby Steps that adds multiplayer to the game.")]
[assembly: AssemblyFileVersion("1.3.2")]
[assembly: AssemblyInformationalVersion("1.3.2+c32baaf3066f84489719f6b43cbaf0715cdaa69b")]
[assembly: AssemblyProduct("BabyStepsMultiplayerClient")]
[assembly: AssemblyTitle("BabyStepsMultiplayerClient")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/caleborchard/Baby-Steps-Multiplayer-Mod-Client")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.3.2.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class IsUnmanagedAttribute : Attribute
	{
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 BabyStepsMultiplayerClient
{
	public class Core : MelonMod
	{
		public const string SERVER_VERSION = "108";

		public static string CLIENT_VERSION;

		public const string cloneText = "(Clone)";

		public static Instance logger;

		public static UIManager uiManager;

		public static NetworkManager networkManager;

		public static InGameHost inGameHost;

		public static Action OnConnectionStateChanged;

		private static ulong _pendingInviteConnect = 0uL;

		private static string _pendingInviteKey = string.Empty;

		private static float _continueBtnFirstSeenAt = -1f;

		private static float _lastContinueClickAt = -10f;

		private static ulong _pendingJoinLobbyCall = 0uL;

		private static ulong _pendingJoinLobbyId = 0uL;

		public override void OnLateInitializeMelon()
		{
			CLIENT_VERSION = ((MelonBase)this).Info.Version;
			logger = ((MelonBase)this).LoggerInstance;
			try
			{
				((MelonBase)this).HarmonyInstance.PatchAll(Assembly.GetExecutingAssembly());
				((MelonBase)this).HarmonyInstance.PatchAll(typeof(MenuInjectionLibrary).Assembly);
			}
			catch (Exception value)
			{
				logger.Error($"Harmony patching failed: {value}");
			}
			ManagedEnumerator.Register();
			try
			{
				SteamClient.Init(0u, false);
				logger.Msg("[Steam] Facepunch initialized for invite callbacks");
			}
			catch (Exception ex) when (ex.Message.Contains("already initialized") || ex.Message.Contains("SteamAPI_SteamInput") || ex.Message.Contains("entry point") || ex.Message.Contains("SteamInput"))
			{
				logger.Msg("[Steam] Facepunch init note: " + ex.Message);
			}
			catch (Exception ex2)
			{
				logger.Warning("[Steam] Facepunch init failed: " + ex2.Message);
			}
			uiManager = new UIManager();
			networkManager = new NetworkManager();
			MultiplayerMenu.Initialize();
			NativeSteamAPI.RegisterLobbyJoinRequestedCallback(delegate(ulong lobbyId)
			{
				logger.Msg($"[Steam] Lobby invite accepted — lobbyId={lobbyId}, calling JoinLobby to fetch host ID…");
				if (_pendingJoinLobbyCall != 0)
				{
					logger.Warning($"[Steam] Overwriting a pending JoinLobby call ({_pendingJoinLobbyCall}) for lobby {_pendingJoinLobbyId}");
				}
				_pendingJoinLobbyCall = NativeSteamAPI.JoinLobby(lobbyId);
				_pendingJoinLobbyId = lobbyId;
				logger.Msg($"[Steam] JoinLobby handle={_pendingJoinLobbyCall} (will poll for result in OnUpdate)");
			});
			NativeSteamAPI.RegisterJoinRequestedCallback(delegate(string connectStr)
			{
				logger.Msg("[Steam] GameRichPresenceJoinRequested fired — connectStr='" + connectStr + "'");
				if (ulong.TryParse(connectStr.Trim(), out var result3) && result3 != 0)
				{
					logger.Msg($"[Steam] Game invite accepted — queuing connect to {result3}");
					_pendingInviteConnect = result3;
				}
				else
				{
					logger.Warning("[Steam] GameRichPresenceJoinRequested: could not parse '" + connectStr + "' as SteamID64");
				}
			});
			try
			{
				SteamFriends.OnGameLobbyJoinRequested += delegate(Lobby lobby, SteamId friend)
				{
					//IL_0003: Unknown result type (might be due to invalid IL or missing references)
					//IL_0042: Unknown result type (might be due to invalid IL or missing references)
					ulong num = SteamId.op_Implicit(((Lobby)(ref lobby)).Id);
					logger.Msg($"[Steam] Facepunch GameLobbyJoinRequested lid={num} friend={friend.Value}");
					if (_pendingJoinLobbyCall != 0)
					{
						logger.Warning($"[Steam] Overwriting pending JoinLobby {_pendingJoinLobbyCall}");
					}
					_pendingJoinLobbyCall = NativeSteamAPI.JoinLobby(num);
					_pendingJoinLobbyId = num;
					logger.Msg($"[Steam] JoinLobby handle={_pendingJoinLobbyCall}");
				};
				logger.Msg("[Steam] Facepunch OnGameLobbyJoinRequested hooked");
			}
			catch (Exception ex3)
			{
				logger.Msg("[Steam] Facepunch GameLobbyJoinRequested hook: " + ex3.Message);
			}
			try
			{
				SteamFriends.OnGameRichPresenceJoinRequested += delegate(Friend friend, string connectStr)
				{
					//IL_0035: 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)
					logger.Msg($"[Steam] Facepunch GameRichPresenceJoinRequested connectStr='{connectStr}' friend={friend.Id.Value}");
					if (ulong.TryParse(connectStr.Trim(), out var result2) && result2 != 0)
					{
						_pendingInviteConnect = result2;
					}
					else
					{
						logger.Warning("[Steam] Facepunch GameRichPresenceJoinRequested: could not parse '" + connectStr + "'");
					}
				};
				logger.Msg("[Steam] Facepunch OnGameRichPresenceJoinRequested hooked");
			}
			catch (Exception ex4)
			{
				logger.Msg("[Steam] Facepunch GameRichPresenceJoinRequested hook: " + ex4.Message);
			}
			try
			{
				string text = NativeSteamAPI.GetLaunchCommandLine().Trim();
				if (!string.IsNullOrEmpty(text) && ulong.TryParse(text, out var result) && result != 0)
				{
					logger.Msg($"[Steam] Launched from game invite, will connect to {result}");
					_pendingInviteConnect = result;
				}
			}
			catch
			{
			}
			logger.Msg("Initialized!");
			VersionCheck.CheckForUpdate();
		}

		public override void OnGUI()
		{
			if (uiManager != null)
			{
				uiManager.Draw();
			}
		}

		public override void OnUpdate()
		{
			if (uiManager == null || networkManager == null)
			{
				return;
			}
			uiManager.Update();
			networkManager.Update();
			inGameHost?.Tick(Time.deltaTime * 1000f);
			MultiplayerMenu.Update();
			if (LocalPlayer.Instance != null)
			{
				LocalPlayer.Instance.Update();
			}
			InGameHost obj = inGameHost;
			if (obj == null || !obj.IsRunning)
			{
				try
				{
					NativeSteamAPI.RunCallbacks();
				}
				catch
				{
				}
				try
				{
					SteamClient.RunCallbacks();
				}
				catch
				{
				}
			}
			if (_pendingJoinLobbyCall != 0)
			{
				bool flag;
				bool failed;
				try
				{
					flag = NativeSteamAPI.IsAPICallCompleted(_pendingJoinLobbyCall, out failed);
				}
				catch (Exception ex)
				{
					logger.Warning("[Steam] IsAPICallCompleted threw: " + ex.Message);
					flag = false;
					failed = false;
				}
				if (flag)
				{
					ulong pendingJoinLobbyCall = _pendingJoinLobbyCall;
					ulong pendingJoinLobbyId = _pendingJoinLobbyId;
					_pendingJoinLobbyCall = 0uL;
					_pendingJoinLobbyId = 0uL;
					logger.Msg($"[Steam] JoinLobby call={pendingJoinLobbyCall} lobby={pendingJoinLobbyId} completed, failed={failed}");
					if (!failed)
					{
						string lobbyData = NativeSteamAPI.GetLobbyData(pendingJoinLobbyId, "bbs_host");
						string lobbyData2 = NativeSteamAPI.GetLobbyData(pendingJoinLobbyId, "bbs_invite_key");
						ulong lobbyOwner = NativeSteamAPI.GetLobbyOwner(pendingJoinLobbyId);
						logger.Msg($"[Steam] Invite lobby {pendingJoinLobbyId}: bbs_host='{lobbyData}' GetLobbyOwner={lobbyOwner} hasInviteKey={!string.IsNullOrEmpty(lobbyData2)}");
						ulong result = 0uL;
						if (!string.IsNullOrEmpty(lobbyData) && lobbyData != "0")
						{
							ulong.TryParse(lobbyData, out result);
						}
						if (result == 0)
						{
							result = lobbyOwner;
						}
						if (result != 0)
						{
							logger.Msg($"[Steam] Resolved invite host SteamID: {result}, queuing connect…");
							_pendingInviteConnect = result;
							_pendingInviteKey = lobbyData2;
						}
						else
						{
							logger.Warning($"[Steam] Could not resolve host SteamID from invite lobby {pendingJoinLobbyId} — bbs_host='{lobbyData}' owner={lobbyOwner}");
						}
					}
					else
					{
						logger.Warning($"[Steam] JoinLobby failed for lobby {pendingJoinLobbyId}");
					}
					try
					{
						NativeSteamAPI.LeaveLobby(pendingJoinLobbyId);
					}
					catch
					{
					}
				}
			}
			if (_pendingInviteConnect != 0L && !networkManager.IsConnected)
			{
				if (!HasLoadedGame())
				{
					Menu me = Menu.me;
					Button val = ((me != null) ? me.ContinueGameButton : null);
					if ((Object)(object)val != (Object)null)
					{
						float realtimeSinceStartup = Time.realtimeSinceStartup;
						if (_continueBtnFirstSeenAt < 0f)
						{
							_continueBtnFirstSeenAt = realtimeSinceStartup;
							logger.Msg("[Invite] ContinueGameButton found — waiting for menu to settle before clicking");
						}
						float num = realtimeSinceStartup - _continueBtnFirstSeenAt;
						float num2 = realtimeSinceStartup - _lastContinueClickAt;
						if (num >= 3f && num2 >= 5f)
						{
							_lastContinueClickAt = realtimeSinceStartup;
							logger.Msg($"[Invite] Clicking ContinueGameButton (interactable={((Selectable)val).interactable}, sinceAppear={num:F1}s, sinceClick={num2:F1}s)");
							((UnityEvent)val.onClick).Invoke();
						}
					}
					else
					{
						_continueBtnFirstSeenAt = -1f;
						float realtimeSinceStartup2 = Time.realtimeSinceStartup;
						if (realtimeSinceStartup2 - _lastContinueClickAt >= 5f)
						{
							_lastContinueClickAt = realtimeSinceStartup2;
							logger.Msg($"[Invite] Waiting for main menu (Menu.me={(((Object)(object)Menu.me != (Object)null) ? "exists" : "null")}, HasLoadedGame={HasLoadedGame()})");
						}
					}
				}
				else
				{
					_continueBtnFirstSeenAt = -1f;
					_lastContinueClickAt = -10f;
					ulong pendingInviteConnect = _pendingInviteConnect;
					string pendingInviteKey = _pendingInviteKey;
					_pendingInviteConnect = 0uL;
					_pendingInviteKey = string.Empty;
					logger.Msg($"[Steam] Auto-connecting to invite host {pendingInviteConnect} (inviteKey={!string.IsNullOrEmpty(pendingInviteKey)})");
					networkManager.ConnectSteam(pendingInviteConnect.ToString(), pendingInviteKey);
				}
			}
			else if (_pendingInviteConnect == 0)
			{
				_continueBtnFirstSeenAt = -1f;
				_lastContinueClickAt = -10f;
			}
			SteamP2PTest.Poll();
			if (MelonDebug.IsEnabled())
			{
				if (Input.GetKeyDown((KeyCode)284))
				{
					networkManager.Connect(ModSettings.connection.Address.Value, ModSettings.connection.Port.Value, ModSettings.connection.Password.Value);
				}
				if (Input.GetKeyDown((KeyCode)285))
				{
					networkManager.Disconnect();
				}
			}
		}

		public override void OnLateUpdate()
		{
			if (networkManager != null)
			{
				if (LocalPlayer.Instance != null)
				{
					LocalPlayer.Instance.LateUpdate();
				}
				networkManager.LateUpdate();
			}
		}

		public override void OnApplicationQuit()
		{
			InGameHost obj = inGameHost;
			if (obj != null && obj.IsRunning)
			{
				inGameHost.Stop();
			}
			networkManager?.Disconnect();
		}

		public static bool HasLoadedGame()
		{
			if ((Object)(object)Menu.me == (Object)null)
			{
				return false;
			}
			return Menu.me.gameInProgress;
		}

		public static void DebugMsg(string msg)
		{
			logger.Msg(msg);
		}

		public static bool RegisterComponent<T>(params Type[] interfaces) where T : class
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			try
			{
				RegisterTypeOptions val = new RegisterTypeOptions();
				val.set_LogSuccess(true);
				val.set_Interfaces(Il2CppInterfaceCollection.op_Implicit(interfaces));
				ClassInjector.RegisterTypeInIl2Cpp<T>(val);
			}
			catch (Exception value)
			{
				logger.Error($"Exception while attempting to Register {typeof(T).Name}: {value}");
				return false;
			}
			return true;
		}
	}
	public static class ModSettings
	{
		public static readonly ConnectionConfig connection = new ConnectionConfig();

		public static readonly PlayerConfig player = new PlayerConfig();

		public static readonly AudioConfig audio = new AudioConfig();

		public static void Load()
		{
			connection.Load();
			player.Load();
			audio.Load();
		}

		public static void Save()
		{
			connection.Save();
			player.Save();
			audio.Save();
		}
	}
}
namespace BabyStepsMultiplayerClient.UI
{
	internal static class InputBindingHelper
	{
		private static readonly bool CaptureLoggingEnabled = true;

		private const string RewiredActionPrefix = "RWACTION:";

		private const string RewiredButtonPrefix = "RWBTN:";

		private const string RewiredAxisPrefix = "RWAXIS:";

		private const float AxisThreshold = 0.5f;

		private const int MaxRawRewiredButtonId = 1023;

		private static readonly Dictionary<string, bool> _previousState = new Dictionary<string, bool>();

		private static readonly int[] _inputActionIds = BuildInputActionIdList();

		private static readonly KeyCode[] _joystickButtonKeyCodes = BuildJoystickButtonKeyCodes();

		public static bool IsInputHeldForCapture()
		{
			if (Input.anyKey)
			{
				return true;
			}
			for (int i = 0; i < _joystickButtonKeyCodes.Length; i++)
			{
				if (Input.GetKey(_joystickButtonKeyCodes[i]))
				{
					return true;
				}
			}
			return false;
		}

		public static bool TryCapturePressedBinding(out string binding, out string displayName)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Invalid comparison between Unknown and I4
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < _joystickButtonKeyCodes.Length; i++)
			{
				KeyCode val = _joystickButtonKeyCodes[i];
				if (Input.GetKeyDown(val))
				{
					binding = ((object)(KeyCode)(ref val)).ToString();
					displayName = ((object)(KeyCode)(ref val)).ToString();
					LogCapture("joystick-keycode", binding, displayName);
					return true;
				}
			}
			foreach (KeyCode value in Enum.GetValues(typeof(KeyCode)))
			{
				KeyCode val2 = value;
				if ((int)val2 == 0 || IsJoystickKeyCode(val2) || !Input.GetKeyDown(val2))
				{
					continue;
				}
				binding = ((object)(KeyCode)(ref val2)).ToString();
				displayName = ((object)(KeyCode)(ref val2)).ToString();
				LogCapture("keyboard", binding, displayName);
				return true;
			}
			Menu me = Menu.me;
			Player val3 = ((me != null) ? me.rwPlayer : null);
			if (val3 != null)
			{
				for (int j = 0; j < _inputActionIds.Length; j++)
				{
					int num = _inputActionIds[j];
					if (val3.GetButtonDown(num))
					{
						if (!TryGetInputActionName(num, out var actionName))
						{
							actionName = "Action_" + num;
						}
						if (!IsAxisLikeAction(num, actionName))
						{
							binding = "RWACTION:" + actionName;
							displayName = FormatActionDisplayName(actionName);
							LogCapture("rewired-action", binding, displayName);
							return true;
						}
					}
				}
				if (TryCaptureAxisDown(out binding, out displayName))
				{
					return true;
				}
				for (int k = 0; k <= 1023; k++)
				{
					if (val3.GetButtonDown(k))
					{
						binding = "RWBTN:" + k;
						displayName = GetRewiredButtonDisplayName(k);
						LogCapture("rewired-raw-button", binding, displayName);
						return true;
					}
				}
			}
			binding = null;
			displayName = null;
			return false;
		}

		public static bool IsPressed(string binding)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (TryParseKeyCode(binding, out var keyCode))
			{
				return Input.GetKey(keyCode);
			}
			if (TryParseRewiredButton(binding, out var actionId))
			{
				Menu me = Menu.me;
				int result;
				if (me == null)
				{
					result = 0;
				}
				else
				{
					Player rwPlayer = me.rwPlayer;
					result = (((rwPlayer != null) ? new bool?(rwPlayer.GetButton(actionId)) : null).GetValueOrDefault() ? 1 : 0);
				}
				return (byte)result != 0;
			}
			if (TryParseRewiredAction(binding, out var actionName) && TryGetInputActionId(actionName, out var actionId2))
			{
				Menu me2 = Menu.me;
				int result2;
				if (me2 == null)
				{
					result2 = 0;
				}
				else
				{
					Player rwPlayer2 = me2.rwPlayer;
					result2 = (((rwPlayer2 != null) ? new bool?(rwPlayer2.GetButton(actionId2)) : null).GetValueOrDefault() ? 1 : 0);
				}
				return (byte)result2 != 0;
			}
			if (TryParseRewiredAxis(binding, out var axisId, out var direction))
			{
				Menu me3 = Menu.me;
				Player val = ((me3 != null) ? me3.rwPlayer : null);
				if (val == null)
				{
					return false;
				}
				float axis = val.GetAxis(axisId);
				return (direction > 0) ? (axis > 0.5f) : (axis < -0.5f);
			}
			return false;
		}

		public static bool IsDown(string binding)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if (TryParseKeyCode(binding, out var keyCode))
			{
				return Input.GetKeyDown(keyCode);
			}
			if (TryParseRewiredButton(binding, out var actionId))
			{
				Menu me = Menu.me;
				int result;
				if (me == null)
				{
					result = 0;
				}
				else
				{
					Player rwPlayer = me.rwPlayer;
					result = (((rwPlayer != null) ? new bool?(rwPlayer.GetButtonDown(actionId)) : null).GetValueOrDefault() ? 1 : 0);
				}
				return (byte)result != 0;
			}
			if (TryParseRewiredAction(binding, out var actionName) && TryGetInputActionId(actionName, out var actionId2))
			{
				Menu me2 = Menu.me;
				int result2;
				if (me2 == null)
				{
					result2 = 0;
				}
				else
				{
					Player rwPlayer2 = me2.rwPlayer;
					result2 = (((rwPlayer2 != null) ? new bool?(rwPlayer2.GetButtonDown(actionId2)) : null).GetValueOrDefault() ? 1 : 0);
				}
				return (byte)result2 != 0;
			}
			if (TryParseRewiredAxis(binding, out var _, out var _))
			{
				bool flag = IsPressed(binding);
				_previousState.TryGetValue(binding, out var value);
				_previousState[binding] = flag;
				return flag && !value;
			}
			return false;
		}

		public static bool IsControllerBinding(string binding)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrWhiteSpace(binding))
			{
				return false;
			}
			if (TryParseKeyCode(binding, out var keyCode))
			{
				return IsJoystickKeyCode(keyCode);
			}
			if (binding.StartsWith("RWACTION:", StringComparison.Ordinal) || binding.StartsWith("RWBTN:", StringComparison.Ordinal) || binding.StartsWith("RWAXIS:", StringComparison.Ordinal))
			{
				return true;
			}
			return false;
		}

		public static string GetDisplayName(string binding)
		{
			if (TryParseRewiredAction(binding, out var actionName))
			{
				return FormatActionDisplayName(actionName);
			}
			if (TryParseRewiredButton(binding, out var actionId))
			{
				return GetRewiredButtonDisplayName(actionId);
			}
			if (TryParseRewiredAxis(binding, out var axisId, out var direction))
			{
				switch (axisId)
				{
				case 13:
					return (direction > 0) ? "AXIS Up" : "AXIS Down";
				case 12:
					return (direction > 0) ? "AXIS Right" : "AXIS Left";
				}
			}
			return binding;
		}

		private static bool TryParseKeyCode(string binding, out KeyCode keyCode)
		{
			if (string.IsNullOrWhiteSpace(binding))
			{
				keyCode = (KeyCode)0;
				return false;
			}
			if (!Enum.TryParse<KeyCode>(binding, ignoreCase: true, out keyCode))
			{
				return false;
			}
			return (int)keyCode != 0;
		}

		private static bool TryParseRewiredButton(string binding, out int actionId)
		{
			actionId = -1;
			if (string.IsNullOrWhiteSpace(binding) || !binding.StartsWith("RWBTN:", StringComparison.Ordinal))
			{
				return false;
			}
			return int.TryParse(binding.Substring("RWBTN:".Length), out actionId);
		}

		private static bool TryParseRewiredAction(string binding, out string actionName)
		{
			actionName = null;
			if (string.IsNullOrWhiteSpace(binding) || !binding.StartsWith("RWACTION:", StringComparison.Ordinal))
			{
				return false;
			}
			actionName = binding.Substring("RWACTION:".Length);
			return !string.IsNullOrWhiteSpace(actionName);
		}

		private static bool TryParseRewiredAxis(string binding, out int axisId, out int direction)
		{
			axisId = -1;
			direction = 0;
			if (string.IsNullOrWhiteSpace(binding) || !binding.StartsWith("RWAXIS:", StringComparison.Ordinal))
			{
				return false;
			}
			string text = binding.Substring("RWAXIS:".Length);
			string[] array = text.Split(':');
			if (array.Length != 2)
			{
				return false;
			}
			if (!int.TryParse(array[0], out axisId))
			{
				return false;
			}
			if (array[1] == "+")
			{
				direction = 1;
				return true;
			}
			if (array[1] == "-")
			{
				direction = -1;
				return true;
			}
			return false;
		}

		private static bool TryCaptureAxisDown(out string binding, out string displayName)
		{
			Menu me = Menu.me;
			Player val = ((me != null) ? me.rwPlayer : null);
			if (val == null)
			{
				binding = null;
				displayName = null;
				return false;
			}
			float axis = val.GetAxis(12);
			float axisPrev = val.GetAxisPrev(12);
			float axis2 = val.GetAxis(13);
			float axisPrev2 = val.GetAxisPrev(13);
			if (axis2 > 0.5f && axisPrev2 <= 0.5f)
			{
				binding = "RWAXIS:" + 13 + ":+";
				displayName = "AXIS Up";
				LogCapture("rewired-axis", binding, displayName);
				return true;
			}
			if (axis2 < -0.5f && axisPrev2 >= -0.5f)
			{
				binding = "RWAXIS:" + 13 + ":-";
				displayName = "AXIS Down";
				LogCapture("rewired-axis", binding, displayName);
				return true;
			}
			if (axis > 0.5f && axisPrev <= 0.5f)
			{
				binding = "RWAXIS:" + 12 + ":+";
				displayName = "AXIS Right";
				LogCapture("rewired-axis", binding, displayName);
				return true;
			}
			if (axis < -0.5f && axisPrev >= -0.5f)
			{
				binding = "RWAXIS:" + 12 + ":-";
				displayName = "AXIS Left";
				LogCapture("rewired-axis", binding, displayName);
				return true;
			}
			binding = null;
			displayName = null;
			return false;
		}

		private static string GetRewiredButtonDisplayName(int actionId)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			if (Enum.IsDefined(typeof(InputActions), actionId))
			{
				InputActions val = (InputActions)actionId;
				return ((object)(InputActions)(ref val)).ToString();
			}
			return "Controller Button " + actionId;
		}

		private static int[] BuildInputActionIdList()
		{
			Array values = Enum.GetValues(typeof(InputActions));
			List<int> list = new List<int>(values.Length);
			HashSet<int> hashSet = new HashSet<int>();
			for (int i = 0; i < values.Length; i++)
			{
				int item = (int)values.GetValue(i);
				if (hashSet.Add(item))
				{
					list.Add(item);
				}
			}
			list.Sort();
			return list.ToArray();
		}

		private static bool TryGetInputActionName(int actionId, out string actionName)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			actionName = null;
			if (!Enum.IsDefined(typeof(InputActions), actionId))
			{
				return false;
			}
			InputActions val = (InputActions)actionId;
			actionName = ((object)(InputActions)(ref val)).ToString();
			return !string.IsNullOrWhiteSpace(actionName);
		}

		private static bool TryGetInputActionId(string actionName, out int actionId)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected I4, but got Unknown
			actionId = -1;
			if (string.IsNullOrWhiteSpace(actionName))
			{
				return false;
			}
			if (!Enum.TryParse<InputActions>(actionName, ignoreCase: true, out InputActions result))
			{
				return false;
			}
			actionId = (int)result;
			return true;
		}

		private static bool IsAxisLikeAction(int actionId, string actionName)
		{
			if (actionId == 12 || actionId == 13)
			{
				return true;
			}
			if (string.IsNullOrWhiteSpace(actionName))
			{
				return false;
			}
			return actionName.IndexOf("Horizontal", StringComparison.OrdinalIgnoreCase) >= 0 || actionName.IndexOf("Vertical", StringComparison.OrdinalIgnoreCase) >= 0;
		}

		private static KeyCode[] BuildJoystickButtonKeyCodes()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			List<KeyCode> list = new List<KeyCode>();
			for (int i = 0; i <= 19; i++)
			{
				if (Enum.TryParse<KeyCode>("JoystickButton" + i, out KeyCode result))
				{
					list.Add(result);
				}
			}
			for (int j = 1; j <= 8; j++)
			{
				for (int k = 0; k <= 19; k++)
				{
					if (Enum.TryParse<KeyCode>("Joystick" + j + "Button" + k, out KeyCode result2))
					{
						list.Add(result2);
					}
				}
			}
			return list.ToArray();
		}

		private static bool IsJoystickKeyCode(KeyCode keyCode)
		{
			string text = ((object)(KeyCode)(ref keyCode)).ToString();
			return text.IndexOf("Joystick", StringComparison.OrdinalIgnoreCase) >= 0;
		}

		private static string FormatActionDisplayName(string actionName)
		{
			if (string.IsNullOrWhiteSpace(actionName))
			{
				return actionName;
			}
			if (actionName.StartsWith("UI", StringComparison.OrdinalIgnoreCase))
			{
				return "DPAD " + actionName.Substring(2);
			}
			return actionName;
		}

		private static void LogCapture(string source, string binding, string displayName)
		{
			if (CaptureLoggingEnabled)
			{
				Core.DebugMsg($"[BindCapture] source={source} binding={binding} display={displayName}");
			}
		}
	}
	public static class MultiplayerMenu
	{
		private enum KeybindCaptureTarget
		{
			None,
			PushToTalk,
			TabMenu,
			ChatMenu
		}

		private static InjectedMenu _menu;

		private static Toggle _collisionToggle;

		private static Toggle _cutsceneToggle;

		private static Toggle _nametagToggle;

		private static Button _pttKeyBtn;

		private static Button _tabMenuKeyBtn;

		private static Button _chatMenuKeyBtn;

		private static Button _audioDeviceBtn;

		private static float _lastAudioDeviceLabelRefresh = -10f;

		private static Image _colorPreviewImage;

		private static KeybindCaptureTarget _keybindCaptureTarget;

		private static bool _waitingForRelease;

		private static BaseInputModule _cachedInputModule;

		private static bool _playerMovementSuppressedForCapture;

		private static bool _playerMovementWasEnabledBeforeCapture;

		private static Button _connectTabBtn;

		private static Button _hostLanTabBtn;

		private static Button _hostSteamTabBtn;

		private static string _lastKnownLanguage;

		private static TMP_Text _lobbyBrowserLabel;

		private static TMP_Text _audioDeviceStaticLabel;

		private static TMP_Text _gainLabel;

		private static Button _tabBtn0;

		private static Button _tabBtn1;

		private static Button _tabBtn2;

		private static Button _tabBtn3;

		private static Button _tabBtn4;

		private static Toggle _microphoneToggle;

		private static Toggle _deafenToggle;

		private static Toggle _pttToggle;

		private static Button _updateAppearanceBtn;

		private static TMP_Text _serverIpLabel;

		private static TMP_Text _serverPortLabel;

		private static TMP_Text _passwordOptLabel;

		private static InputFieldInfo _serverIpInputInfo;

		private static InputFieldInfo _serverPortInputInfo;

		private static InputFieldInfo _lanPasswordInputInfo;

		private static InputFieldInfo _hostingPasswordInputInfo;

		private static TMP_Text _pwEnterTmp;

		private static TMP_Text _pwBackTmp;

		private const int PublicMainPort = 7777;

		private const int PublicMainStatusPort = 7778;

		private const string PublicMainName = "Public Main";

		private static SteamLobbyBrowser _lobbyBrowser;

		private static readonly List<ServerInfo> _foundLobbies = new List<ServerInfo>();

		private static readonly List<ServerInfo> _displayLobbies = new List<ServerInfo>();

		private static readonly List<Button> _lobbyButtons = new List<Button>();

		private static Button _refreshBtn;

		private const int PageSize = 5;

		private static int _lobbyPage = 0;

		private static Button _prevPageBtn;

		private static TMP_Text _pageLabel;

		private static Button _nextPageBtn;

		private static (int PlayerCount, int MaxPlayers, bool IsLocked)? _publicMainStatus;

		private static Task<(int PlayerCount, int MaxPlayers, bool IsLocked)?>? _publicMainQueryTask;

		private static ServerInfo _connectedServerInfo;

		private static int _lastDisplayedPlayerCount = -1;

		private static bool _buttonsWereReady = false;

		private static ServerInfo _pendingLockedLobby;

		private static string _pendingJoinPassword = string.Empty;

		private static GameObject _pwCanvas;

		private static TMP_Text _pwTitle;

		private static Button _pwInputBtn;

		private static InputFieldInfo _pwInputInfo;

		private static float _pwEnterDebounce = -10f;

		private static Sprite _lockSprite;

		private static readonly GameObject[] _lobbyLockIcons = (GameObject[])(object)new GameObject[5];

		private static Button _pwEnterBtn;

		private static Button _pwBackBtn;

		private static float _lastAutoLobbyRefresh = -30f;

		private static string _steamJoinId = string.Empty;

		private static Button _hostingPasswordBtn;

		private static bool _steamJoinInProgress = false;

		private static ulong _ownLobbyId;

		private static float _lastHostSteamClickTime = -10f;

		private static float _lastConnectClickTime = -10f;

		private static float _lastLobbyClickTime = -10f;

		public static bool IsCapturingKeybind => _keybindCaptureTarget != KeybindCaptureTarget.None;

		private static string PublicMainAddress
		{
			get
			{
				string text = ModSettings.connection.PublicMainIpOverride?.Value;
				return (!string.IsNullOrEmpty(text)) ? text : "bbsmm.mooo.com";
			}
		}

		public static void Initialize()
		{
			if (_menu == null)
			{
				MenuInjectionLibrary.Logger = Core.logger;
				MenuInjectionLibrary.IsCapturingKeybindProvider = () => IsCapturingKeybind;
				MenuInjectionLibrary.IsOverlayBlockingMenuProvider = () => (Object)(object)_pwCanvas != (Object)null && _pwCanvas.activeSelf;
				MenuInjectionLibrary.OnChatKeyboardCancelled += delegate
				{
					Core.uiManager.showChatTab = false;
				};
				ModSettings.Load();
				_lobbyBrowser = new SteamLobbyBrowser();
				((SteamLobbyBrowserSource)_lobbyBrowser).ServersFound += OnLobbiesFound;
				ILanguage currentLanguage = LanguageManager.GetCurrentLanguage();
				_lastKnownLanguage = LanguageManager.CurrentLanguage;
				_menu = MenuInjectionLibrary.CreateMenu("Multiplayer").AddTab(currentLanguage.TabLobby, (Action<TabBuilder>)ConfigureServersTab).AddTab(currentLanguage.TabPlayer, (Action<TabBuilder>)ConfigurePlayerTab)
					.AddTab(currentLanguage.TabGeneral, (Action<TabBuilder>)ConfigureGeneralTab)
					.AddTab(currentLanguage.TabAudio, (Action<TabBuilder>)ConfigureAudioTab)
					.AddTab(currentLanguage.TabLAN, (Action<TabBuilder>)ConfigureConnectionTab)
					.AddFixedButton(currentLanguage.ButtonBack, (UnityAction)null)
					.WithMargin(136f, 125f)
					.Build();
				Core.OnConnectionStateChanged = (Action)Delegate.Combine(Core.OnConnectionStateChanged, new Action(RefreshConnectionState));
				Core.OnConnectionStateChanged = (Action)Delegate.Combine(Core.OnConnectionStateChanged, new Action(RefreshHostState));
				Core.OnConnectionStateChanged = (Action)Delegate.Combine(Core.OnConnectionStateChanged, new Action(RefreshHostSteamState));
				_publicMainQueryTask = DedicatedServerQuery.QueryAsync(PublicMainAddress, 7778);
				SteamLobbyBrowser lobbyBrowser = _lobbyBrowser;
				if (lobbyBrowser != null)
				{
					((SteamLobbyBrowserSource)lobbyBrowser).Refresh();
				}
				RebuildLobbyUI();
			}
		}

		public static void Update()
		{
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			string currentLanguage = LanguageManager.CurrentLanguage;
			if (currentLanguage != _lastKnownLanguage)
			{
				_lastKnownLanguage = currentLanguage;
				RefreshLocalizableText();
			}
			_lobbyBrowser?.Poll();
			if (!_buttonsWereReady && _lobbyButtons.Count > 0)
			{
				_buttonsWereReady = true;
				InjectedMenu menu = _menu;
				_tabBtn0 = ((menu != null) ? menu.GetTab(0) : null);
				InjectedMenu menu2 = _menu;
				_tabBtn1 = ((menu2 != null) ? menu2.GetTab(1) : null);
				InjectedMenu menu3 = _menu;
				_tabBtn2 = ((menu3 != null) ? menu3.GetTab(2) : null);
				InjectedMenu menu4 = _menu;
				_tabBtn3 = ((menu4 != null) ? menu4.GetTab(3) : null);
				InjectedMenu menu5 = _menu;
				_tabBtn4 = ((menu5 != null) ? menu5.GetTab(4) : null);
				RefreshLocalizableText();
				RepositionPaginationRow();
				InjectedMenu menu6 = _menu;
				Button val = ((menu6 != null) ? menu6.GetFixedButton(0) : null);
				if ((Object)(object)val != (Object)null)
				{
					RectTransform component = ((Component)val).GetComponent<RectTransform>();
					if ((Object)(object)component != (Object)null)
					{
						component.anchoredPosition = new Vector2(component.anchoredPosition.x, component.anchoredPosition.y - 135f);
					}
				}
				RebuildLobbyUI();
				if (_publicMainQueryTask == null || _publicMainQueryTask.IsCompleted)
				{
					_publicMainQueryTask = DedicatedServerQuery.QueryAsync(PublicMainAddress, 7778);
				}
			}
			if (_publicMainQueryTask != null && _publicMainQueryTask.IsCompleted)
			{
				_publicMainStatus = _publicMainQueryTask.Result;
				_publicMainQueryTask = null;
				RebuildLobbyUI();
			}
			if (Core.networkManager.IsConnected && _connectedServerInfo != null)
			{
				int num = Core.networkManager.players.Values.Count((RemotePlayer p) => p.firstAppearanceApplication) + 1;
				if (num != _lastDisplayedPlayerCount)
				{
					_lastDisplayedPlayerCount = num;
					RebuildLobbyUI();
				}
			}
			else if (!Core.networkManager.IsConnected && _connectedServerInfo != null)
			{
				_connectedServerInfo = null;
				_lastDisplayedPlayerCount = -1;
				RebuildLobbyUI();
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (!Core.networkManager.IsConnected)
			{
				InGameHost inGameHost = Core.inGameHost;
				if ((inGameHost == null || !inGameHost.IsRunning) && realtimeSinceStartup - _lastAutoLobbyRefresh >= 30f)
				{
					_lastAutoLobbyRefresh = realtimeSinceStartup;
					SteamLobbyBrowser lobbyBrowser = _lobbyBrowser;
					if (lobbyBrowser != null)
					{
						((SteamLobbyBrowserSource)lobbyBrowser).Refresh();
					}
					if (_publicMainQueryTask == null || _publicMainQueryTask.IsCompleted)
					{
						_publicMainQueryTask = DedicatedServerQuery.QueryAsync(PublicMainAddress, 7778);
					}
				}
			}
			if ((Object)(object)_audioDeviceBtn != (Object)null)
			{
				float realtimeSinceStartup2 = Time.realtimeSinceStartup;
				if (realtimeSinceStartup2 - _lastAudioDeviceLabelRefresh >= 3f)
				{
					_lastAudioDeviceLabelRefresh = realtimeSinceStartup2;
					SetBtnText(_audioDeviceBtn, GetAudioDeviceLabel());
				}
			}
			if (_keybindCaptureTarget == KeybindCaptureTarget.None)
			{
				return;
			}
			UpdateGameplayInputSuppressionForCapture();
			string binding;
			string displayName;
			if (_waitingForRelease)
			{
				if (!InputBindingHelper.IsInputHeldForCapture())
				{
					_waitingForRelease = false;
				}
			}
			else if (InputBindingHelper.TryCapturePressedBinding(out binding, out displayName))
			{
				ApplyCapturedKeybind(binding, displayName);
			}
		}

		private static void ConfigurePlayerTab(TabBuilder tab)
		{
			//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_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			ILanguage currentLanguage = LanguageManager.GetCurrentLanguage();
			Color value = ModSettings.player.SuitColor.Value;
			_updateAppearanceBtn = tab.AddButton(currentLanguage.UpdateNameAndAppearance, UnityAction.op_Implicit((Action)OnUpdateAppearanceClicked));
			tab.AddInputField(currentLanguage.Nickname, UnityAction<string>.op_Implicit((Action<string>)delegate(string v)
			{
				ModSettings.player.Nickname.Value = v;
			}), ModSettings.player.Nickname.Value);
			Slider val2 = null;
			Slider val3 = null;
			Slider val4 = null;
			val2 = tab.AddSlider("R:", 0f, 1f, value.r, UnityAction<float>.op_Implicit((Action<float>)delegate(float val)
			{
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				Color value4 = ModSettings.player.SuitColor.Value;
				value4.r = val;
				ModSettings.player.SuitColor.Value = value4;
				RefreshColorPreview();
			}), false);
			val3 = tab.AddSlider("G:", 0f, 1f, value.g, UnityAction<float>.op_Implicit((Action<float>)delegate(float val)
			{
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				Color value3 = ModSettings.player.SuitColor.Value;
				value3.g = val;
				ModSettings.player.SuitColor.Value = value3;
				RefreshColorPreview();
			}), false);
			val4 = tab.AddSlider("B:", 0f, 1f, value.b, UnityAction<float>.op_Implicit((Action<float>)delegate(float val)
			{
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				Color value2 = ModSettings.player.SuitColor.Value;
				value2.b = val;
				ModSettings.player.SuitColor.Value = value2;
				RefreshColorPreview();
			}), false);
			_colorPreviewImage = tab.AddImage(value, 40f);
		}

		private static void ConfigureConnectionTab(TabBuilder tab)
		{
			ILanguage currentLanguage = LanguageManager.GetCurrentLanguage();
			_serverIpLabel = tab.AddLabel(currentLanguage.ServerIP);
			tab.AddInputField(currentLanguage.ServerIP, UnityAction<string>.op_Implicit((Action<string>)delegate(string v)
			{
				ModSettings.connection.Address.Value = v;
			}), ModSettings.connection.Address.Value);
			_serverIpInputInfo = MenuInjectionLibrary.LastCreatedInputFieldInfo;
			_serverPortLabel = tab.AddLabel(currentLanguage.ServerPort);
			tab.AddInputField(currentLanguage.ServerPort, UnityAction<string>.op_Implicit((Action<string>)delegate(string v)
			{
				if (int.TryParse(v, out var result))
				{
					ModSettings.connection.Port.Value = result;
				}
			}), ModSettings.connection.Port.Value.ToString());
			_serverPortInputInfo = MenuInjectionLibrary.LastCreatedInputFieldInfo;
			_passwordOptLabel = tab.AddLabel(currentLanguage.PasswordOptional);
			tab.AddInputField(currentLanguage.PasswordOptional, UnityAction<string>.op_Implicit((Action<string>)delegate(string v)
			{
				ModSettings.connection.Password.Value = v;
			}), ModSettings.connection.Password.Value);
			_lanPasswordInputInfo = MenuInjectionLibrary.LastCreatedInputFieldInfo;
			_connectTabBtn = tab.AddButton(GetConnectLabel(), UnityAction.op_Implicit((Action)OnConnectClicked));
			_hostLanTabBtn = tab.AddButton(GetHostLabel(), UnityAction.op_Implicit((Action)OnHostClicked));
		}

		private static void ConfigureGeneralTab(TabBuilder tab)
		{
			_collisionToggle = tab.AddToggle(GetCollisionToggleLabel(), ModSettings.player.Collisions.Value, UnityAction<bool>.op_Implicit((Action<bool>)OnCollisionToggled));
			_cutsceneToggle = tab.AddToggle(GetCutsceneToggleLabel(), ModSettings.player.CutscenePlayerVisibility.Value, UnityAction<bool>.op_Implicit((Action<bool>)OnCutsceneToggled));
			_nametagToggle = tab.AddToggle(GetNametagToggleLabel(), ModSettings.player.ShowNametags.Value, UnityAction<bool>.op_Implicit((Action<bool>)OnNametagToggled));
			_tabMenuKeyBtn = tab.AddButton(GetTabMenuKeyLabel(), UnityAction.op_Implicit((Action)OnTabMenuKeyClicked));
			_chatMenuKeyBtn = tab.AddButton(GetChatMenuKeyLabel(), UnityAction.op_Implicit((Action)OnChatMenuKeyClicked));
		}

		private static void ConfigureAudioTab(TabBuilder tab)
		{
			_microphoneToggle = tab.AddToggle(GetMicrophoneToggleLabel(), ModSettings.audio.MicrophoneEnabled.Value, UnityAction<bool>.op_Implicit((Action<bool>)OnMicrophoneToggled));
			_deafenToggle = tab.AddToggle(GetDeafenToggleLabel(), ModSettings.audio.Deafened.Value, UnityAction<bool>.op_Implicit((Action<bool>)OnDeafenToggled));
			_pttToggle = tab.AddToggle(GetPushToTalkToggleLabel(), ModSettings.audio.PushToTalk.Value, UnityAction<bool>.op_Implicit((Action<bool>)OnPushToTalkToggled));
			_pttKeyBtn = tab.AddButton(GetPttKeyLabel(), UnityAction.op_Implicit((Action)OnPttKeyClicked));
			((Selectable)_pttKeyBtn).interactable = ModSettings.audio.PushToTalk.Value;
			Slider val2 = null;
			_gainLabel = tab.AddLabel(GetGainLabel());
			val2 = tab.AddSlider("", 0f, 3f, ModSettings.audio.MicrophoneGain.Value, UnityAction<float>.op_Implicit((Action<float>)delegate(float val)
			{
				ModSettings.audio.MicrophoneGain.Value = val;
				LocalPlayer.Instance?.mic.SetGain(val);
				if ((Object)(object)_gainLabel != (Object)null)
				{
					_gainLabel.text = GetGainLabel();
					_gainLabel.ForceMeshUpdate(false, false);
				}
			}), false);
			_audioDeviceStaticLabel = tab.AddLabel(LanguageManager.GetCurrentLanguage().AudioDevice);
			_audioDeviceBtn = tab.AddButton(GetAudioDeviceLabel(), UnityAction.op_Implicit((Action)OnAudioDeviceCycled));
		}

		private static void ConfigureServersTab(TabBuilder tab)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: 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)
			tab.AddImage(Color.clear, 10f);
			ILanguage currentLanguage = LanguageManager.GetCurrentLanguage();
			_hostSteamTabBtn = tab.AddButton(GetHostSteamLabel(), UnityAction.op_Implicit((Action)OnHostSteamClicked));
			_hostingPasswordBtn = tab.AddInputField(currentLanguage.LobbyPassword, UnityAction<string>.op_Implicit((Action<string>)delegate(string v)
			{
				ModSettings.connection.HostPassword.Value = v;
			}), ModSettings.connection.HostPassword.Value);
			_hostingPasswordInputInfo = MenuInjectionLibrary.LastCreatedInputFieldInfo;
			tab.AddImage(Color.clear, 24f);
			_lobbyBrowserLabel = tab.AddLabel(currentLanguage.LobbyBrowser);
			_refreshBtn = tab.AddButton(currentLanguage.Refresh, UnityAction.op_Implicit((Action)OnRefreshLobbies));
			_prevPageBtn = tab.AddButton("<", UnityAction.op_Implicit((Action)OnPrevPage));
			_pageLabel = tab.AddLabel("1/1");
			_nextPageBtn = tab.AddButton(">", UnityAction.op_Implicit((Action)OnNextPage));
			for (int i = 0; i < 5; i++)
			{
				int captured = i;
				Button val = tab.AddButton("---", UnityAction.op_Implicit((Action)delegate
				{
					OnLobbyButtonClicked(captured);
				}));
				((Selectable)val).interactable = false;
				ColorBlock colors = ((Selectable)val).colors;
				((ColorBlock)(ref colors)).disabledColor = new Color(((ColorBlock)(ref colors)).disabledColor.r, ((ColorBlock)(ref colors)).disabledColor.g, ((ColorBlock)(ref colors)).disabledColor.b, 0.8f);
				((Selectable)val).colors = colors;
				_lobbyButtons.Add(val);
			}
			BuildPasswordPopup();
		}

		private static void OnConnectClicked()
		{
			if (Core.networkManager.IsConnected)
			{
				Core.networkManager.Disconnect();
				return;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (!(realtimeSinceStartup - _lastConnectClickTime < 0.5f))
			{
				_lastConnectClickTime = realtimeSinceStartup;
				ModSettings.Save();
				Core.networkManager.Connect(ModSettings.connection.Address.Value, ModSettings.connection.Port.Value, ModSettings.connection.Password.Value);
			}
		}

		private static void OnHostSteamClicked()
		{
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (realtimeSinceStartup - _lastHostSteamClickTime < 0.5f)
			{
				return;
			}
			_lastHostSteamClickTime = realtimeSinceStartup;
			bool flag = Core.inGameHost?.IsRunning ?? false;
			if (!flag && Core.networkManager.IsConnected)
			{
				Core.networkManager.Disconnect();
				return;
			}
			if (flag)
			{
				Core.inGameHost?.Stop();
				Core.inGameHost = null;
				_ownLobbyId = 0uL;
				Core.networkManager.Disconnect();
				Core.uiManager.notificationsUI.AddMessage(LanguageManager.GetCurrentLanguage().StoppedHosting);
				RefreshHostSteamState();
				OnRefreshLobbies();
				return;
			}
			ModSettings.Save();
			string value = ModSettings.connection.HostPassword.Value;
			InGameHost inGameHost = new InGameHost();
			inGameHost.PlayerJoined += delegate(string name)
			{
				Core.uiManager.notificationsUI.AddMessage(string.Format(LanguageManager.GetCurrentLanguage().PlayerJoinedSession, name));
			};
			inGameHost.PlayerLeft += delegate(string name)
			{
				Core.uiManager.notificationsUI.AddMessage(string.Format(LanguageManager.GetCurrentLanguage().PlayerLeftSession, name));
			};
			LocalLoopbackClientTransport loopback = inGameHost.StartSteam(value);
			inGameHost.LobbyCreated += delegate(string lobbyIdStr)
			{
				ulong.TryParse(lobbyIdStr, out _ownLobbyId);
				RefreshHostSteamState();
				Core.networkManager.ConnectLoopback(loopback);
				OnRefreshLobbies();
			};
			Core.inGameHost = inGameHost;
			Core.uiManager.notificationsUI.AddMessage(LanguageManager.GetCurrentLanguage().CreatingLobby);
		}

		private static void OnHostClicked()
		{
			InGameHost inGameHost = Core.inGameHost;
			if (inGameHost != null && inGameHost.IsRunning)
			{
				Core.inGameHost?.Stop();
				Core.inGameHost = null;
				Core.networkManager.Disconnect();
				Core.uiManager.notificationsUI.AddMessage(LanguageManager.GetCurrentLanguage().StoppedHosting);
				RefreshHostState();
				return;
			}
			ModSettings.Save();
			int value = ModSettings.connection.Port.Value;
			string value2 = ModSettings.connection.Password.Value;
			InGameHost inGameHost2 = new InGameHost();
			inGameHost2.Log += delegate(string msg)
			{
				Core.logger.Msg("[Host] " + msg);
			};
			inGameHost2.PlayerJoined += delegate(string name)
			{
				Core.uiManager.notificationsUI.AddMessage(string.Format(LanguageManager.GetCurrentLanguage().PlayerJoinedSession, name));
			};
			inGameHost2.PlayerLeft += delegate(string name)
			{
				Core.uiManager.notificationsUI.AddMessage(string.Format(LanguageManager.GetCurrentLanguage().PlayerLeftSession, name));
			};
			inGameHost2.Start(value, value2);
			Core.inGameHost = inGameHost2;
			Core.networkManager.Connect("127.0.0.1", value, value2);
			Core.uiManager.notificationsUI.AddMessage(string.Format(LanguageManager.GetCurrentLanguage().HostingOnPort, value));
		}

		private static void OnJoinBySteamId()
		{
			if (_steamJoinInProgress)
			{
				return;
			}
			if (string.IsNullOrWhiteSpace(_steamJoinId))
			{
				Core.uiManager.notificationsUI.AddMessage("Enter the host's SteamID64 first.");
				return;
			}
			if (Core.networkManager.IsConnected)
			{
				Core.uiManager.notificationsUI.AddMessage("Disconnect first.");
				return;
			}
			_steamJoinInProgress = true;
			try
			{
				ModSettings.Save();
				Core.networkManager.ConnectSteam(_steamJoinId.Trim(), ModSettings.connection.Password.Value);
			}
			finally
			{
				_steamJoinInProgress = false;
			}
		}

		private static void OnP2PTestListenToggle()
		{
			if (SteamP2PTest.IsListening)
			{
				SteamP2PTest.StopListening();
			}
			else
			{
				SteamP2PTest.StartListening();
			}
		}

		private static void OnP2PTestPing()
		{
			if (!ulong.TryParse(_steamJoinId?.Trim(), out var result) || result == 0)
			{
				Core.uiManager.notificationsUI.AddMessage("Enter host SteamID64 in the field above first.");
			}
			else
			{
				SteamP2PTest.SendPing(result);
			}
		}

		private static void OnPrevPage()
		{
			int num = Mathf.Max(1, Mathf.CeilToInt((float)_displayLobbies.Count / 5f));
			_lobbyPage = (_lobbyPage - 1 + num) % num;
			RebuildLobbyUI();
		}

		private static void OnNextPage()
		{
			int num = Mathf.Max(1, Mathf.CeilToInt((float)_displayLobbies.Count / 5f));
			_lobbyPage = (_lobbyPage + 1) % num;
			RebuildLobbyUI();
		}

		private static void RepositionPaginationRow()
		{
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_prevPageBtn == (Object)null || (Object)(object)_pageLabel == (Object)null || (Object)(object)_nextPageBtn == (Object)null)
			{
				return;
			}
			RectTransform component = ((Component)_prevPageBtn).GetComponent<RectTransform>();
			RectTransform component2 = ((Component)_pageLabel).GetComponent<RectTransform>();
			RectTransform component3 = ((Component)_nextPageBtn).GetComponent<RectTransform>();
			if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || (Object)(object)component3 == (Object)null)
			{
				return;
			}
			Transform parent = ((Transform)component).parent;
			RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null);
			float num;
			if ((Object)(object)val != (Object)null)
			{
				Rect rect = val.rect;
				if (((Rect)(ref rect)).width > 10f)
				{
					rect = val.rect;
					num = ((Rect)(ref rect)).width;
					goto IL_00c1;
				}
			}
			num = 800f;
			goto IL_00c1;
			IL_00c1:
			float num2 = num;
			float rowY = component.anchoredPosition.y;
			float num3 = num2 - 180f;
			Place(component, 0f, 90f);
			Place(component2, 90f, num3);
			Place(component3, 90f + num3, 90f);
			TMP_Text componentInChildren = ((Component)_prevPageBtn).GetComponentInChildren<TMP_Text>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.fontStyle = (FontStyles)1;
				componentInChildren.ForceMeshUpdate(false, false);
			}
			TMP_Text componentInChildren2 = ((Component)_nextPageBtn).GetComponentInChildren<TMP_Text>(true);
			if ((Object)(object)componentInChildren2 != (Object)null)
			{
				componentInChildren2.fontStyle = (FontStyles)1;
				componentInChildren2.ForceMeshUpdate(false, false);
			}
			_pageLabel.alignment = (TextAlignmentOptions)514;
			_pageLabel.fontSize = 20f;
			_pageLabel.ForceMeshUpdate(false, false);
			foreach (Button lobbyButton in _lobbyButtons)
			{
				RectTransform component4 = ((Component)lobbyButton).GetComponent<RectTransform>();
				if ((Object)(object)component4 != (Object)null)
				{
					component4.anchoredPosition += new Vector2(0f, 124f);
				}
			}
			void Place(RectTransform rt, float x, float w)
			{
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0022: Unknown result type (might be due to invalid IL or missing references)
				//IL_0038: 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)
				//IL_005d: Unknown result type (might be due to invalid IL or missing references)
				rt.anchorMin = new Vector2(0f, 1f);
				rt.anchorMax = new Vector2(0f, 1f);
				rt.pivot = new Vector2(0f, 1f);
				rt.sizeDelta = new Vector2(w, 52f);
				rt.anchoredPosition = new Vector2(x, rowY);
			}
		}

		private static void OnRefreshLobbies()
		{
			SetBtnText(_refreshBtn, LanguageManager.GetCurrentLanguage().Refreshing);
			foreach (Button lobbyButton in _lobbyButtons)
			{
				SetBtnText(lobbyButton, "---");
				((Selectable)lobbyButton).interactable = false;
			}
			_lastAutoLobbyRefresh = Time.realtimeSinceStartup;
			_publicMainQueryTask = DedicatedServerQuery.QueryAsync(PublicMainAddress, 7778);
			SteamLobbyBrowser lobbyBrowser = _lobbyBrowser;
			if (lobbyBrowser != null)
			{
				((SteamLobbyBrowserSource)lobbyBrowser).Refresh();
			}
		}

		private static void RebuildLobbyUI()
		{
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Expected O, but got Unknown
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Expected O, but got Unknown
			//IL_03a4: Unknown result type (might be due to invalid IL or missing references)
			_displayLobbies.Clear();
			InGameHost inGameHost = Core.inGameHost;
			if (inGameHost != null && inGameHost.IsRunning && _ownLobbyId != 0)
			{
				string personaName = NativeSteamAPI.GetPersonaName();
				bool flag = !string.IsNullOrEmpty(ModSettings.connection.HostPassword.Value);
				string name = (flag ? "\ud83d\udd12 " : "") + (string.IsNullOrEmpty(personaName) ? $"{NativeSteamAPI.GetLocalSteamId()}  (this session)" : (personaName + "'s Session  (this session)"));
				_displayLobbies.Add(new ServerInfo
				{
					Name = name,
					IsPasswordProtected = flag,
					Address = NativeSteamAPI.GetLocalSteamId().ToString(),
					SessionId = _ownLobbyId.ToString(),
					PlayerCount = Math.Max(1, Core.inGameHost.PlayerCount),
					MaxPlayers = 16,
					Type = (ServerType)1
				});
			}
			bool flag2 = _publicMainStatus?.IsLocked ?? false;
			_displayLobbies.Add(new ServerInfo
			{
				Name = (flag2 ? "\ud83d\udd12 " : "") + "Public Main",
				Address = PublicMainAddress,
				Port = 7777,
				PlayerCount = (_publicMainStatus?.PlayerCount ?? (-1)),
				MaxPlayers = (_publicMainStatus?.MaxPlayers ?? 16),
				IsPasswordProtected = flag2,
				Type = (ServerType)0
			});
			InGameHost inGameHost2 = Core.inGameHost;
			string ownAddress = ((inGameHost2 != null && inGameHost2.IsRunning && _ownLobbyId != 0L) ? NativeSteamAPI.GetLocalSteamId().ToString() : null);
			List<ServerInfo> collection = (from s in _foundLobbies
				where (int)s.Type != 1 || s.Address != ownAddress
				orderby s.PlayerCount descending
				select s).ToList();
			_displayLobbies.AddRange(collection);
			int num = Mathf.Max(1, Mathf.CeilToInt((float)_displayLobbies.Count / 5f));
			_lobbyPage = Mathf.Clamp(_lobbyPage, 0, num - 1);
			int num2 = _lobbyPage * 5;
			if ((Object)(object)_pageLabel != (Object)null)
			{
				_pageLabel.text = $"{_lobbyPage + 1}/{num}";
				_pageLabel.ForceMeshUpdate(false, false);
			}
			bool interactable = !Core.networkManager.IsConnected;
			int num3 = (Core.networkManager.IsConnected ? (Core.networkManager.players.Values.Count((RemotePlayer p) => p.firstAppearanceApplication) + 1) : (-2));
			for (int i = 0; i < _lobbyButtons.Count; i++)
			{
				int num4 = num2 + i;
				if (num4 < _displayLobbies.Count)
				{
					ServerInfo val = _displayLobbies[num4];
					int num5 = ((_connectedServerInfo != null && _connectedServerInfo.Address == val.Address && ((int)_connectedServerInfo.Type != 0 || _connectedServerInfo.Port == val.Port) && num3 >= 0) ? num3 : val.PlayerCount);
					string value = val.Name.Replace("\ud83d\udd12 ", string.Empty);
					string value2 = ((num5 < 0) ? "?" : num5.ToString());
					SetBtnText(_lobbyButtons[i], $"{value}  ({value2}/{val.MaxPlayers})");
					((Selectable)_lobbyButtons[i]).interactable = interactable;
					SetLobbyLockIcon(i, val.IsPasswordProtected);
				}
				else
				{
					SetBtnText(_lobbyButtons[i], "---");
					((Selectable)_lobbyButtons[i]).interactable = false;
					SetLobbyLockIcon(i, show: false);
				}
			}
		}

		private static void JoinServer(ServerInfo info, string password)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Invalid comparison between Unknown and I4
			_connectedServerInfo = info;
			_lastDisplayedPlayerCount = -1;
			ModSettings.Save();
			string arg = info.Name.Replace("\ud83d\udd12 ", string.Empty);
			string message = string.Format(LanguageManager.GetCurrentLanguage().JoiningServer, arg);
			if ((int)info.Type == 0)
			{
				Core.networkManager.Connect(info.Address, info.Port, password);
				Core.uiManager.notificationsUI.AddMessage(message);
			}
			else
			{
				Core.networkManager.ConnectSteam(info.Address, password);
				Core.uiManager.notificationsUI.AddMessage(message);
			}
		}

		private static void OnLobbyButtonClicked(int slot)
		{
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (realtimeSinceStartup - _lastLobbyClickTime < 0.5f)
			{
				return;
			}
			_lastLobbyClickTime = realtimeSinceStartup;
			int num = _lobbyPage * 5 + slot;
			if (num < _displayLobbies.Count)
			{
				ServerInfo val = _displayLobbies[num];
				if (val.IsPasswordProtected)
				{
					ShowPasswordPrompt(val);
				}
				else
				{
					JoinServer(val, string.Empty);
				}
			}
		}

		private static void ShowPasswordPrompt(ServerInfo lobby)
		{
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			_pendingLockedLobby = lobby;
			_pendingJoinPassword = string.Empty;
			if ((Object)(object)_pwTitle != (Object)null)
			{
				string arg = lobby.Name.Replace("\ud83d\udd12 ", string.Empty).Trim();
				_pwTitle.text = string.Format(LanguageManager.GetCurrentLanguage().PasswordForSession, arg);
				_pwTitle.ForceMeshUpdate(false, false);
			}
			if (_pwInputInfo != null)
			{
				_pwInputInfo.Value = string.Empty;
				if ((Object)(object)_pwInputInfo.DisplayText != (Object)null)
				{
					_pwInputInfo.DisplayText.text = _pwInputInfo.Placeholder;
					((Graphic)_pwInputInfo.DisplayText).color = _pwInputInfo.PlaceholderColor;
					_pwInputInfo.DisplayText.ForceMeshUpdate(false, false);
				}
			}
			GameObject pwCanvas = _pwCanvas;
			if (pwCanvas != null)
			{
				pwCanvas.SetActive(true);
			}
			MenuInjectionLibrary.ShowPopupDim(new Color(0f, 0f, 0f, 0.78f));
			MenuInjectionLibrary.OverlayNavigableItems = ((IEnumerable<GameObject>)(object)new GameObject[3]
			{
				((Object)(object)_pwInputBtn != (Object)null) ? ((Component)_pwInputBtn).gameObject : null,
				((Object)(object)_pwEnterBtn != (Object)null) ? ((Component)_pwEnterBtn).gameObject : null,
				((Object)(object)_pwBackBtn != (Object)null) ? ((Component)_pwBackBtn).gameObject : null
			}).Where((GameObject g) => (Object)(object)g != (Object)null).ToArray();
			EventSystem current = EventSystem.current;
			if (current != null)
			{
				current.SetSelectedGameObject(((Object)(object)_pwEnterBtn != (Object)null) ? ((Component)_pwEnterBtn).gameObject : null);
			}
		}

		private static void BuildPasswordPopup()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0221: Unknown result type (might be due to invalid IL or missing references)
			//IL_0290: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Expected O, but got Unknown
			//IL_031a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0329: Unknown result type (might be due to invalid IL or missing references)
			//IL_0383: Unknown result type (might be due to invalid IL or missing references)
			//IL_038d: Expected O, but got Unknown
			//IL_040d: Unknown result type (might be due to invalid IL or missing references)
			//IL_041c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_pwCanvas != (Object)null)
			{
				return;
			}
			_pwCanvas = new GameObject("BBSPasswordPopup");
			Object.DontDestroyOnLoad((Object)(object)_pwCanvas);
			Canvas val = _pwCanvas.AddComponent<Canvas>();
			val.renderMode = (RenderMode)0;
			val.sortingOrder = 9999;
			_pwCanvas.AddComponent<CanvasScaler>();
			_pwCanvas.AddComponent<GraphicRaycaster>();
			GameObject val2 = new GameObject("Panel");
			val2.transform.SetParent(_pwCanvas.transform, false);
			((Graphic)val2.AddComponent<Image>()).color = new Color(0.12f, 0.12f, 0.12f, 0.97f);
			RectTransform component = val2.GetComponent<RectTransform>();
			SetRTCenter(component, new Vector2(400f, 260f), Vector2.zero);
			Button hostSteamTabBtn = _hostSteamTabBtn;
			object obj;
			if (hostSteamTabBtn == null)
			{
				obj = null;
			}
			else
			{
				TMP_Text componentInChildren = ((Component)hostSteamTabBtn).GetComponentInChildren<TMP_Text>(true);
				obj = ((componentInChildren != null) ? ((Component)componentInChildren).gameObject : null);
			}
			GameObject val3 = (GameObject)obj;
			if ((Object)(object)val3 != (Object)null)
			{
				GameObject val4 = Object.Instantiate<GameObject>(val3, val2.transform);
				val4.SetActive(true);
				_pwTitle = val4.GetComponent<TMP_Text>();
				if ((Object)(object)_pwTitle != (Object)null)
				{
					_pwTitle.text = "Enter password:";
					_pwTitle.alignment = (TextAlignmentOptions)514;
					_pwTitle.enableAutoSizing = false;
					_pwTitle.fontSize = 24f;
					_pwTitle.ForceMeshUpdate(false, false);
				}
				SetRTCenter(val4.GetComponent<RectTransform>(), new Vector2(360f, 70f), new Vector2(0f, 90f));
			}
			_pwInputBtn = MenuInjectionLibrary.AddInputField("type password...", UnityAction<string>.op_Implicit((Action<string>)delegate(string v)
			{
				_pendingJoinPassword = v;
			}), string.Empty, component);
			_pwInputInfo = MenuInjectionLibrary.LastCreatedInputFieldInfo;
			if ((Object)(object)_pwInputBtn != (Object)null)
			{
				SetRTCenter(((Component)_pwInputBtn).GetComponent<RectTransform>(), new Vector2(340f, 52f), new Vector2(0f, 15f));
			}
			if ((Object)(object)_refreshBtn != (Object)null)
			{
				GameObject val5 = Object.Instantiate<GameObject>(((Component)_refreshBtn).gameObject, val2.transform);
				val5.SetActive(true);
				_pwEnterBtn = val5.GetComponent<Button>();
				if ((Object)(object)_pwEnterBtn != (Object)null)
				{
					((Selectable)_pwEnterBtn).interactable = true;
					_pwEnterBtn.onClick = new ButtonClickedEvent();
					((UnityEvent)_pwEnterBtn.onClick).AddListener(UnityAction.op_Implicit((Action)OnPopupEnterClicked));
				}
				_pwEnterTmp = val5.GetComponentInChildren<TMP_Text>(true);
				if ((Object)(object)_pwEnterTmp != (Object)null)
				{
					_pwEnterTmp.text = "Enter";
					_pwEnterTmp.ForceMeshUpdate(false, false);
				}
				SetRTCenter(val5.GetComponent<RectTransform>(), new Vector2(140f, 52f), new Vector2(-85f, -72f));
				GameObject val6 = Object.Instantiate<GameObject>(((Component)_refreshBtn).gameObject, val2.transform);
				val6.SetActive(true);
				_pwBackBtn = val6.GetComponent<Button>();
				if ((Object)(object)_pwBackBtn != (Object)null)
				{
					((Selectable)_pwBackBtn).interactable = true;
					_pwBackBtn.onClick = new ButtonClickedEvent();
					((UnityEvent)_pwBackBtn.onClick).AddListener(UnityAction.op_Implicit((Action)HidePasswordPopup));
				}
				_pwBackTmp = val6.GetComponentInChildren<TMP_Text>(true);
				if ((Object)(object)_pwBackTmp != (Object)null)
				{
					_pwBackTmp.text = "Back";
					_pwBackTmp.ForceMeshUpdate(false, false);
				}
				SetRTCenter(val6.GetComponent<RectTransform>(), new Vector2(140f, 52f), new Vector2(85f, -72f));
				if ((Object)(object)_pwEnterBtn != (Object)null && (Object)(object)_pwBackBtn != (Object)null)
				{
					SetExplicitNav(_pwEnterBtn, _pwBackBtn, _pwBackBtn);
					SetExplicitNav(_pwBackBtn, _pwEnterBtn, _pwEnterBtn);
				}
			}
			_pwCanvas.SetActive(false);
		}

		private static void SetExplicitNav(Button btn, Button left, Button right)
		{
			Navigation navigation = ((Selectable)btn).navigation;
			navigation.mode = (Mode)4;
			navigation.selectOnLeft = (Selectable)(object)left;
			navigation.selectOnRight = (Selectable)(object)right;
			navigation.selectOnUp = null;
			navigation.selectOnDown = null;
			((Selectable)btn).navigation = navigation;
		}

		private static void SetRTFill(RectTransform rt)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			rt.anchorMin = Vector2.zero;
			rt.anchorMax = Vector2.one;
			rt.sizeDelta = Vector2.zero;
			rt.anchoredPosition = Vector2.zero;
		}

		private static void SetRTCenter(RectTransform rt, Vector2 size, Vector2 pos)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(0.5f, 0.5f);
			rt.pivot = val;
			Vector2 anchorMin = (rt.anchorMax = val);
			rt.anchorMin = anchorMin;
			rt.sizeDelta = size;
			rt.anchoredPosition = pos;
		}

		private static void HidePasswordPopup()
		{
			_pendingLockedLobby = null;
			_pendingJoinPassword = string.Empty;
			MenuInjectionLibrary.ForceCloseMouseTyping();
			MenuInjectionLibrary.OverlayNavigableItems = null;
			MenuInjectionLibrary.HidePopupDim();
			GameObject pwCanvas = _pwCanvas;
			if (pwCanvas != null)
			{
				pwCanvas.SetActive(false);
			}
			EventSystem current = EventSystem.current;
			if (current != null)
			{
				current.SetSelectedGameObject((GameObject)null);
			}
		}

		private static void HidePasswordPrompt()
		{
			HidePasswordPopup();
		}

		private static void OnPopupEnterClicked()
		{
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (!(realtimeSinceStartup - _pwEnterDebounce < 0.5f))
			{
				_pwEnterDebounce = realtimeSinceStartup;
				if (_pendingLockedLobby != null)
				{
					string pendingJoinPassword = _pendingJoinPassword;
					ServerInfo pendingLockedLobby = _pendingLockedLobby;
					HidePasswordPopup();
					JoinServer(pendingLockedLobby, pendingJoinPassword);
				}
			}
		}

		private static Sprite GetLockSprite()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: 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_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_lockSprite != (Object)null)
			{
				return _lockSprite;
			}
			Texture2D val = new Texture2D(24, 24, (TextureFormat)4, false);
			((Texture)val).filterMode = (FilterMode)0;
			Color32[] px = (Color32[])(object)new Color32[576];
			Color32 c2 = default(Color32);
			((Color32)(ref c2))..ctor(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue);
			Color32 val2 = default(Color32);
			((Color32)(ref val2))..ctor((byte)0, (byte)0, (byte)0, (byte)0);
			for (int i = 0; i < px.Length; i++)
			{
				px[i] = val2;
			}
			Rect(2, 1, 21, 10, c2);
			Rect(5, 8, 8, 19, c2);
			Rect(15, 8, 18, 19, c2);
			Rect(5, 17, 18, 20, c2);
			Rect(9, 10, 14, 17, val2);
			val.SetPixels32(Il2CppStructArray<Color32>.op_Implicit(px));
			val.Apply();
			_lockSprite = Sprite.Create(val, new Rect(0f, 0f, 24f, 24f), new Vector2(0.5f, 0.5f), 24f);
			return _lockSprite;
			void Rect(int x0, int y0, int x1, int y1, Color32 c)
			{
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0031: Unknown result type (might be due to invalid IL or missing references)
				for (int j = y0; j <= y1; j++)
				{
					for (int k = x0; k <= x1; k++)
					{
						if (k >= 0 && k < 24 && j >= 0 && j < 24)
						{
							px[j * 24 + k] = c;
						}
					}
				}
			}
		}

		private static void SetLobbyLockIcon(int slot, bool show)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Expected O, but got Unknown
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			if (slot < 0 || slot >= _lobbyButtons.Count)
			{
				return;
			}
			Button val = _lobbyButtons[slot];
			if (!((Object)(object)val == (Object)null))
			{
				if ((Object)(object)_lobbyLockIcons[slot] == (Object)null)
				{
					GameObject val2 = new GameObject("LockIcon");
					val2.transform.SetParent(((Component)val).transform, false);
					Image val3 = val2.AddComponent<Image>();
					val3.sprite = GetLockSprite();
					val3.preserveAspect = true;
					RectTransform component = val2.GetComponent<RectTransform>();
					component.anchorMin = new Vector2(0f, 0.72f);
					component.anchorMax = new Vector2(0f, 0.72f);
					component.pivot = new Vector2(0f, 0.5f);
					component.anchoredPosition = new Vector2(4f, 0f);
					component.sizeDelta = new Vector2(20f, 20f);
					_lobbyLockIcons[slot] = val2;
				}
				_lobbyLockIcons[slot].SetActive(show);
				TMP_Text componentInChildren = ((Component)val).GetComponentInChildren<TMP_Text>(true);
				if ((Object)(object)componentInChildren != (Object)null)
				{
					Vector4 margin = componentInChildren.margin;
					margin.x = (show ? 30f : 0f);
					componentInChildren.margin = margin;
				}
			}
		}

		private static void OnLobbiesFound(IReadOnlyList<ServerInfo> servers)
		{
			_foundLobbies.Clear();
			_foundLobbies.AddRange(servers);
			SetBtnText(_refreshBtn, LanguageManager.GetCurrentLanguage().Refresh);
			if (!Core.networkManager.IsConnected && !(Core.inGameHost?.IsRunning ?? false))
			{
				string text = NativeSteamAPI.GetLocalSteamId().ToString();
				string key = "bbs_invite_" + text;
				foreach (ServerInfo server in servers)
				{
					if (string.IsNullOrEmpty(server.SessionId) || !ulong.TryParse(server.SessionId, out var result) || result == 0 || NativeSteamAPI.GetLobbyData(result, key) != "1")
					{
						continue;
					}
					Core.logger.Msg($"[Steam] Invite detected in lobby {result} — joining {server.Name}");
					Core.uiManager.notificationsUI.AddMessage("Auto-joining " + server.Name.Replace("\ud83d\udd12 ", "") + "…");
					Core.networkManager.ConnectSteam(server.Address, string.Empty);
					break;
				}
			}
			RebuildLobbyUI();
		}

		private static void OnMicrophoneToggled(bool enabled)
		{
			ModSettings.audio.MicrophoneEnabled.Value = enabled;
			LocalPlayer.Instance?.SetMicrophoneEnabled(enabled);
		}

		private static void OnDeafenToggled(bool enabled)
		{
			ModSettings.audio.Deafened.Value = enabled;
		}

		private static void OnPushToTalkToggled(bool enabled)
		{
			ModSettings.audio.PushToTalk.Value = enabled;
			LocalPlayer.Instance?.SetPushToTalkEnabled(enabled);
			if ((Object)(object)_pttKeyBtn != (Object)null)
			{
				((Selectable)_pttKeyBtn).interactable = enabled;
			}
		}

		private static void OnAudioDeviceCycled()
		{
			string[] availableDevicesStatic = BBSMicrophoneCapture.GetAvailableDevicesStatic();
			if (availableDevicesStatic != null && availableDevicesStatic.Length != 0)
			{
				int num = (ModSettings.audio.SelectedMicrophoneIndex.Value + 1) % availableDevicesStatic.Length;
				ModSettings.audio.SelectedMicrophoneIndex.Value = num;
				LocalPlayer.Instance?.SetMicrophoneDevice(num);
				ModSettings.Save();
				SetBtnText(_audioDeviceBtn, GetAudioDeviceLabel());
			}
		}

		private static void OnPttKeyClicked()
		{
			BeginCapture(KeybindCaptureTarget.PushToTalk);
			SetBtnText(_pttKeyBtn, LanguageManager.GetCurrentLanguage().PressAnyKey);
		}

		private static void OnTabMenuKeyClicked()
		{
			BeginCapture(KeybindCaptureTarget.TabMenu);
			SetBtnText(_tabMenuKeyBtn, LanguageManager.GetCurrentLanguage().PressAnyKey);
		}

		private static void OnChatMenuKeyClicked()
		{
			BeginCapture(KeybindCaptureTarget.ChatMenu);
			SetBtnText(_chatMenuKeyBtn, LanguageManager.GetCurrentLanguage().PressAnyKey);
		}

		private static void OnCollisionToggled(bool enabled)
		{
			if (!Core.networkManager.IsConnected)
			{
				if ((Object)(object)_collisionToggle != (Object)null && _collisionToggle.isOn != ModSettings.player.Collisions.Value)
				{
					_collisionToggle.isOn = ModSettings.player.Collisions.Value;
				}
			}
			else
			{
				if (ModSettings.player.Collisions.Value == enabled)
				{
					return;
				}
				ModSettings.player.Collisions.Value = enabled;
				Core.networkManager.SendCollisionToggle(enabled);
				foreach (KeyValuePair<byte, RemotePlayer> player in Core.networkManager.players)
				{
					if (ModSettings.player.Collisions.Value && player.Value.netCollisionsEnabled)
					{
						player.Value.EnableCollision();
					}
					else
					{
						player.Value.DisableCollision();
					}
				}
			}
		}

		private static void OnCutsceneToggled(bool enabled)
		{
			if (!Core.networkManager.IsConnected)
			{
				if ((Object)(object)_cutsceneToggle != (Object)null && _cutsceneToggle.isOn != ModSettings.player.CutscenePlayerVisibility.Value)
				{
					_cutsceneToggle.isOn = ModSettings.player.CutscenePlayerVisibility.Value;
				}
			}
			else
			{
				ModSettings.player.CutscenePlayerVisibility.Value = enabled;
			}
		}

		private static void OnNametagToggled(bool enabled)
		{
			if (!Core.networkManager.IsConnected)
			{
				if ((Object)(object)_nametagToggle != (Object)null && _nametagToggle.isOn != ModSettings.player.ShowNametags.Value)
				{
					_nametagToggle.isOn = ModSettings.player.ShowNametags.Value;
				}
			}
			else
			{
				ModSettings.player.ShowNametags.Value = enabled;
			}
		}

		private static void OnUpdateAppearanceClicked()
		{
			if (Core.networkManager.IsConnected)
			{
				ModSettings.Save();
				Core.networkManager.SendPlayerInformation();
				LocalPlayer.Instance?.ApplySuitColor();
				Core.uiManager.notificationsUI.AddMessage(LanguageManager.GetCurrentLanguage().AppearanceUpdated);
			}
		}

		private static void RefreshConnectionState()
		{
			SetBtnText(_connectTabBtn, GetConnectLabel());
			RefreshHostSteamState();
		}

		private static void RefreshHostState()
		{
			SetBtnText(_hostLanTabBtn, GetHostLabel());
			if ((Object)(object)_hostLanTabBtn != (Object)null)
			{
				((Selectable)_hostLanTabBtn).interactable = !Core.networkManager.IsConnected || (Core.inGameHost?.IsRunning ?? false);
			}
		}

		private static void RefreshHostSteamState()
		{
			SetBtnText(_hostSteamTabBtn, GetHostSteamLabel());
			RebuildLobbyUI();
		}

		private static void RefreshColorPreview()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_colorPreviewImage != (Object)null)
			{
				((Graphic)_colorPreviewImage).color = ModSettings.player.SuitColor.Value;
			}
		}

		private static string GetConnectLabel()
		{
			NetworkManager networkManager = Core.networkManager;
			return (networkManager != null && networkManager.IsConnected) ? LanguageManager.GetCurrentLanguage().Disconnect : LanguageManager.GetCurrentLanguage().Connect;
		}

		private static string GetHostLabel()
		{
			ILanguage currentLanguage = LanguageManager.GetCurrentLanguage();
			InGameHost inGameHost = Core.inGameHost;
			return (inGameHost != null && inGameHost.IsRunning) ? currentLanguage.StopHosting : currentLanguage.HostLAN;
		}

		private static string GetHostSteamLabel()
		{
			ILanguage currentLanguage = LanguageManager.GetCurrentLanguage();
			InGameHost inGameHost = Core.inGameHost;
			if (inGameHost != null && inGameHost.IsRunning)
			{
				return currentLanguage.StopHosting;
			}
			NetworkManager networkManager = Core.networkManager;
			if (networkManager != null && networkManager.IsConnected)
			{
				return currentLanguage.Disconnect;
			}
			return currentLanguage.HostLobby;
		}

		private static string GetMicrophoneToggleLabel()
		{
			return GetNeutralToggleLabel(LanguageManager.GetCurrentLanguage().EnableMicrophone, LanguageManager.GetCurrentLanguage().DisableMicrophone);
		}

		private static string GetDeafenToggleLabel()
		{
			return GetNeutralToggleLabel(LanguageManager.GetCurrentLanguage().Deafen, LanguageManager.GetCurrentLanguage().Undeafen);
		}

		private static string GetPushToTalkToggleLabel()
		{
			return GetNeutralToggleLabel(LanguageManager.GetCurrentLanguage().EnablePushToTalk, LanguageManager.GetCurrentLanguage().DisablePushToTalk);
		}

		private static string GetCollisionToggleLabel()
		{
			return GetNeutralToggleLabel(LanguageManager.GetCurrentLanguage().EnableCollisions, LanguageManager.GetCurrentLanguage().DisableCollisions);
		}

		private static string GetCutsceneToggleLabel()
		{
			return GetNeutralToggleLabel(LanguageManager.GetCurrentLanguage().EnablePlayerCutsceneVisibility, LanguageManager.GetCurrentLanguage().DisablePlayerCutsceneVisibility);
		}

		private static string GetNametagToggleLabel()
		{
			return GetNeutralToggleLabel(LanguageManager.GetCurrentLanguage().EnableNametags, LanguageManager.GetCurrentLanguage().DisableNametags);
		}

		private static string GetPttKeyLabel()
		{
			ILanguage currentLanguage = LanguageManager.GetCurrentLanguage();
			return currentLanguage.PushToTalkKey + " " + InputBindingHelper.GetDisplayName(ModSettings.audio.PushToTalkKey.Value);
		}

		private static string GetTabMenuKeyLabel()
		{
			ILanguage currentLanguage = LanguageManager.GetCurrentLanguage();
			return currentLanguage.PlayerListKeyLabel + " " + InputBindingHelper.GetDisplayName(ModSettings.player.TabMenuKey.Value);
		}

		private static string GetChatMenuKeyLabel()
		{
			ILanguage currentLanguage = LanguageManager.GetCurrentLanguage();
			return currentLanguage.ChatMenuKeyLabel + " " + InputBindingHelper.GetDisplayName(ModSettings.player.ChatMenuKey.Value);
		}

		private static string GetGainLabel()
		{
			return $"{LanguageManager.GetCurrentLanguage().MicrophoneGain} {ModSettings.audio.MicrophoneGain.Value:F2}x";
		}

		private static string GetAudioDeviceLabel()
		{
			string[] availableDevicesStatic = BBSMicrophoneCapture.GetAvailableDevicesStatic();
			if (availableDevicesStatic == null || availableDevicesStatic.Length == 0)
			{
				return LanguageManager.GetCurrentLanguage().NoDevicesFound;
			}
			int num = Mathf.Clamp(ModSettings.audio.SelectedMicrophoneIndex.Value, 0, availableDevicesStatic.Length - 1);
			return availableDevicesStatic[num];
		}

		private static string GetNeutralToggleLabel(string enabledText, string disabledText)
		{
			if (string.IsNullOrEmpty(enabledText))
			{
				return disabledText ?? string.Empty;
			}
			if (string.IsNullOrEmpty(disabledText))
			{
				return enabledText;
			}
			if (disabledText.EndsWith(enabledText, StringComparison.OrdinalIgnoreCase))
			{
				return enabledText;
			}
			if (enabledText.EndsWith(disabledText, StringComparison.OrdinalIgnoreCase))
			{
				return disabledText;
			}
			string[] array = enabledText.Split(' ');
			string[] array2 = disabledText.Split(' ');
			int num = array.Length - 1;
			int num2 = array2.Length - 1;
			int num3 = 0;
			while (num >= 0 && num2 >= 0 && string.Equals(array[num], array2[num2], StringComparison.OrdinalIgnoreCase))
			{
				num3++;
				num--;
				num2--;
			}
			if (num3 > 0)
			{
				int startIndex = array.Length - num3;
				string text = string.Join(" ", array, startIndex, num3).Trim();
				if (!string.IsNullOrEmpty(text))
				{
					return text;
				}
			}
			return enabledText;
		}

		private static void RefreshLocalizableText()
		{
			ILanguage currentLanguage = LanguageManager.GetCurrentLanguage();
			InjectedMenu menu = _menu;
			if (menu != null)
			{
				menu.SetMainButtonLabel(currentLanguage.MultiplayerTitle);
			}
			InjectedMenu menu2 = _menu;
			if (menu2 != null)
			{
				menu2.SetTabName(0, currentLanguage.TabLobby);
			}
			InjectedMenu menu3 = _menu;
			if (menu3 != null)
			{
				menu3.SetTabName(1, currentLanguage.TabPlayer);
			}
			InjectedMenu menu4 = _menu;
			if (menu4 != null)
			{
				menu4.SetTabName(2, currentLanguage.TabGeneral);
			}
			InjectedMenu menu5 = _menu;
			if (menu5 != null)
			{
				menu5.SetTabName(3, currentLanguage.TabAudio);
			}
			InjectedMenu menu6 = _menu;
			if (menu6 != null)
			{
				menu6.SetTabName(4, currentLanguage.TabLAN);
			}
			SetBtnText(_tabBtn0, currentLanguage.TabLobby);
			SetBtnText(_tabBtn1, currentLanguage.TabPlayer);
			SetBtnText(_tabBtn2, currentLanguage.TabGeneral);
			SetBtnText(_tabBtn3, currentLanguage.TabAudio);
			SetBtnText(_tabBtn4, currentLanguage.TabLAN);
			InjectedMenu menu7 = _menu;
			SetBtnText((menu7 != null) ? menu7.GetFixedButton(0) : null, currentLanguage.ButtonBack);
			SetBtnText(_connectTabBtn, GetConnectLabel());
			SetBtnText(_hostLanTabBtn, GetHostLabel());
			SetBtnText(_hostSteamTabBtn, GetHostSteamLabel());
			SetBtnText(_refreshBtn, currentLanguage.Refresh);
			RefreshInputFieldPlaceholder(_hostingPasswordInputInfo, currentLanguage.LobbyPassword);
			TMP_FontAsset currentToggleFont = MenuInjectionLibrary.GetCurrentToggleFont();
			SetToggleText(_collisionToggle, GetCollisionToggleLabel(), currentToggleFont);
			SetToggleText(_cutsceneToggle, GetCutsceneToggleLabel(), currentToggleFont);
			SetToggleText(_nametagToggle, GetNametagToggleLabel(), currentToggleFont);
			SetBtnText(_tabMenuKeyBtn, GetTabMenuKeyLabel());
			SetBtnText(_chatMenuKeyBtn, GetChatMenuKeyLabel());
			SetToggleText(_microphoneToggle, GetMicrophoneToggleLabel(), currentToggleFont);
			SetToggleText(_deafenToggle, GetDeafenToggleLabel(), currentToggleFont);
			SetToggleText(_pttToggle, GetPushToTalkToggleLabel(), currentToggleFont);
			SetBtnText(_pttKeyBtn, GetPttKeyLabel());
			SetBtnText(_audioDeviceBtn, GetAudioDeviceLabel());
			if ((Object)(object)_audioDeviceStaticLabel != (Object)null)
			{
				_audioDeviceStaticLabel.text = currentLanguage.AudioDevice;
				_audioDeviceStaticLabel.ForceMeshUpdate(false, false);
			}
			if ((Object)(object)_gainLabel != (Object)null)
			{
				_gainLabel.text = GetGainLabel();
				_gainLabel.ForceMeshUpdate(false, false);
			}
			if ((Object)(object)_lobbyBrowserLabel != (Object)null)
			{
				_lobbyBrowserLabel.text = currentLanguage.LobbyBrowser;
				_lobbyBrowserLabel.ForceMeshUpdate(false, false);
			}
			SetBtnText(_updateAppearanceBtn, currentLanguage.UpdateNameAndAppearance);
			SetLabelText(_serverIpLabel, currentLanguage.ServerIP);
			SetLabelText(_serverPortLabel, currentLanguage.ServerPort);
			SetLabelText(_passwordOptLabel, currentLanguage.PasswordOptional);
			RefreshInputFieldPlaceholder(_serverIpInputInfo, currentLanguage.ServerIP);
			RefreshInputFieldPlaceholder(_serverPortInputInfo, currentLanguage.ServerPort);
			RefreshInputFieldPlaceholder(_lanPasswordInputInfo, currentLanguage.PasswordOptional);
			if ((Object)(object)_pwEnterTmp != (Object)null)
			{
				_pwEnterTmp.text = currentLanguage.Enter;
				_pwEnterTmp.ForceMeshUpdate(false, false);
			}
			if ((Object)(object)_pwBackTmp != (Object)null)
			{
				_pwBackTmp.text = currentLanguage.ButtonBack;
				_pwBackTmp.ForceMeshUpdate(false, false);
			}
		}

		private static void SetLabelText(TMP_Text label, string text)
		{
			if (!((Object)(object)label == (Object)null))
			{
				label.text = text;
				label.ForceMeshUpdate(false, false);
			}
		}

		private static void RefreshInputFieldPlaceholder(InputFieldInfo info, string placeholder)
		{
			if (info != null)
			{
				info.Placeholder = placeholder;
				if (string.IsNullOrEmpty(info.Value) && (Object)(object)info.DisplayText != (Object)null)
				{
					info.DisplayText.text = placeholder;
					info.DisplayText.ForceMeshUpdate(false, false);
				}
			}
		}

		private static void SetBtnText(Button btn, string text)
		{
			if (!((Object)(object)btn == (Object)null))
			{
				TMP_Text componentInChildren = ((Component)btn).GetComponentInChildren<TMP_Text>(true);
				if (!((Object)(object)componentInChildren == (Object)null))
				{
					componentInChildren.text = text;
					componentInChildren.ForceMeshUpdate(false, false);
				}
			}
		}

		private static void SetToggleText(Toggle toggle, string text, TMP_FontAsset font = null)
		{
			if ((Object)(object)toggle == (Object)null)
			{
				return;
			}
			TMP_Text componentInChildren = ((Component)toggle).GetComponentInChildren<TMP_Text>(true);
			if (!((Object)(object)componentInChildren == (Object)null))
			{
				componentInChildren.text = text;
				if ((Object)(object)font != (Object)null)
				{
					componentInChildren.font = font;
				}
				componentInChildren.ForceMeshUpdate(false, false);
			}
		}

		private static void ApplyCapturedKeybind(string binding, string displayName)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			KeyCode val = (KeyCode)27;
			if (string.Equals(binding, ((object)(KeyCode)(ref val)).ToString(), StringComparison.OrdinalIgnoreCase))
			{
				CancelCapture();
				return;
			}
			switch (_keybindCaptureTarget)
			{
			case KeybindCaptureTarget.PushToTalk:
				ModSettings.audio.PushToTalkKey.Value = binding;
				SetBtnText(_pttKeyBtn, "Bind Key: " + displayName);
				break;
			case KeybindCaptureTarget.TabMenu:
				ModSettings.player.TabMenuKey.Value = binding;
				SetBtnText(_tabMenuKeyBtn, GetTabMenuKeyLabel());
				break;
			case KeybindCaptureTarget.ChatMenu:
				ModSettings.player.ChatMenuKey.Value = binding;
				SetBtnText(_chatMenuKeyBtn, GetChatMenuKeyLabel());
				break;
			}
			_keybindCaptureTarget = KeybindCaptureTarget.None;
			ModSettings.Save();
			EndCapture();
		}

		private static void BeginCapture(KeybindCaptureTarget target)
		{
			if (_keybindCaptureTarget != 0)
			{
				return;
			}
			_keybindCaptureTarget = target;
			_waitingForRelease = true;
			UpdateGameplayInputSuppressionForCapture();
			if ((Object)(object)EventSystem.current != (Object)null)
			{
				_cachedInputModule = EventSystem.current.currentInputModule;
				if ((Object)(object)_cachedInputModule != (Object)null)
				{
					((Behaviour)_cachedInputModule).enabled = false;
				}
			}
		}

		private static void CancelCapture()
		{
			switch (_keybindCaptureTarget)
			{
			case KeybindCaptureTarget.PushToTalk:
				SetBtnText(_pttKeyBtn, GetPttKeyLabel());
				break;
			case KeybindCaptureTarget.TabMenu:
				SetBtnText(_tabMenuKeyBtn, GetTabMenuKeyLabel());
				break;
			case KeybindCaptureTarget.ChatMenu:
				SetBtnText(_chatMenuKeyBtn, GetChatMenuKeyLabel());
				break;
			}
			EndCapture();
		}

		private static void UpdateGameplayInputSuppressionForCapture()
		{
			PlayerMovement val = LocalPlayer.Instance?.playerMovement;
			if ((Object)(object)val == (Object)null)
			{
				_playerMovementSuppressedForCapture = false;
			}
			else if (IsCapturingKeybind)
			{
				if (!_playerMovementSuppressedForCapture)
				{
					_playerMovementWasEnabledBeforeCapture = ((Behaviour)val).enabled;
					if (_playerMovementWasEnabledBeforeCapture)
					{
						((Behaviour)val).enabled = false;
					}
					_playerMovementSuppressedForCapture = true;
				}
			}
			else if (_playerMovementSuppressedForCapture)
			{
				((Behaviour)val).enabled = _playerMovementWasEnabledBeforeCapture;
				_playerMovementSuppressedForCapture = false;
			}
		}

		private static void EndCapture()
		{
			if ((Object)(object)_cachedInputModule != (Object)null)
			{
				((Behaviour)_cachedInputModule).enabled = true;
			}
			_keybindCaptureTarget = KeybindCaptureTarget.None;
			_waitingForRelease = false;
			UpdateGameplayInputSuppressionForCapture();
		}
	}
	public class RuntimeFoldout
	{
		private bool isExpanded;

		private string label;

		public RuntimeFoldout(string label, bool defaultState = false)
		{
			this.label = label;
			isExpanded = defaultState;
		}

		public bool Draw(Action contents)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//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_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: 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)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Expected O, but got Unknown
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			Rect rect = GUILayoutUtility.GetRect(new GUIContent(label), StyleManager.Styles.Button);
			if (GUI.Button(rect, "", StyleManager.Styles.Button))
			{
				isExpanded = !isExpanded;
			}
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(((Rect)(ref rect)).x + 10f, ((Rect)(ref rect)).y, 20f, ((Rect)(ref rect)).height);
			GUI.Label(val, isExpanded ? "▼" : "▶", StyleManager.Styles.RuntimeFoldoutButton);
			GUIStyle val2 = new GUIStyle(GUI.skin.label)
			{
				alignment = (TextAnchor)4,
				fontStyle = StyleManager.Styles.Button.fontStyle,
				fontSize = StyleManager.Styles.Button.fontSize
			};
			val2.normal.textColor = StyleManager.Styles.Button.normal.textColor;
			GUIStyle val3 = val2;
			GUI.Label(rect, label, val3);
			if (isExpanded && contents != null)
			{
				GUILayout.BeginVertical(StyleManager.Styles.Box, (Il2CppReferenceArray<GUILayoutOption>)null);
				contents();
				GUILayout.EndVertical();
			}
			return isExpanded;
		}

		public void SetLabel(string newLabel)
		{
			label = newLabel;
		}

		public void SetExpanded(bool expanded)
		{
			isExpanded = expanded;
		}
	}
	public class RuntimeWindow
	{
		private const float REFERENCE_HEIGHT = 1080f;

		public float ScrollbarWidth = 16f;

		public bool IsOpen;

		public bool IsDraggable = true;

		public bool ShouldDrawBox = true;

		public bool ShouldDrawScrollBar = true;

		public bool ShouldDrawContentBacker = true;

		public bool ShouldAutoResizeHeight;

		public float MinResizeHeight = 10f;

		public float MaxResizeHeight;

		public string Label;

		private float _contentHeight;

		private Rect _windowRect = default(Rect);

		private Vector2 _scrollPos;

		private Rect _windowHeaderRect = default(Rect);

		private Rect _windowContentRect = default(Rect);

		private Rect _windowScrollViewRect = default(Rect);

		private Rect _windowScrollRect = default(Rect);

		private Rect _scrollBarRect = default(Rect);

		private bool _hasClicked;

		private bool _isDragging;

		private Vector2 _dragOffset = default(Vector2);

		private Vector2 _posCache = default(Vector2);

		private Vector2 _sizeCache = default(Vector2);

		private float ScaleFactor => (float)Screen.height / 1080f;

		public Vector2 Position
		{
			get
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				return _posCache;
			}
			set
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				_posCache.x = value.x;
				_posCache.y = value.y;
				((Rect)(ref _windowRect)).position = _posCache;
			}
		}

		public Vector2 Size
		{
			get
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				return _sizeCache;
			}
			set
			{
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				_sizeCache.x = value.x;
				_sizeCache.y = value.y;
				((Rect)(ref _windowRect)).size = _sizeCache;
			}
		}

		public RuntimeWindow(string label, int id, Vector2 defaultPos = default(Vector2), Vector2 defaultSize = default(Vector2), bool defaultState = false)
		{
			//IL_0038: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
	

Mods/BabyStepsNetworking.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Numerics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Threading.Tasks;
using BabyStepsNetworking.Bandwidth;
using BabyStepsNetworking.Client;
using BabyStepsNetworking.Extensions;
using BabyStepsNetworking.Host;
using BabyStepsNetworking.Packets;
using BabyStepsNetworking.Shared;
using BabyStepsNetworking.Transport;
using LiteNetLib;
using LiteNetLib.Layers;
using LiteNetLib.Utils;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("BabyStepsNetworking")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("BabyStepsNetworking")]
[assembly: AssemblyTitle("BabyStepsNetworking")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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;
		}
	}
	internal static class IsExternalInit
	{
	}
}
namespace BabyStepsNetworking.Transport
{
	public sealed class CompositeServerTransport : IServerTransport
	{
		private sealed class Entry
		{
			public IServerTransport Transport;

			public int Offset;

			public Entry(IServerTransport t, int offset)
			{
				Transport = t;
				Offset = offset;
			}
		}

		private const int Range = 100000;

		private readonly Entry[] _entries;

		public IEnumerable<int> ConnectedPeerIds => _entries.SelectMany((Entry e) => e.Transport.ConnectedPeerIds.Select((int id) => id + e.Offset));

		public bool IsRunning => _entries.Any((Entry e) => e.Transport.IsRunning);

		public string TransportName => string.Join("+", _entries.Select((Entry e) => e.Transport.TransportName));

		public event Action<int>? PeerConnected;

		public event Action<int, string>? PeerDisconnected;

		public event Action<int, byte[]>? PacketReceived;

		public CompositeServerTransport(params IServerTransport[] transports)
		{
			_entries = transports.Select((IServerTransport t, int i) => new Entry(t, i * 100000)).ToArray();
			Entry[] entries = _entries;
			foreach (Entry entry in entries)
			{
				Entry captured = entry;
				entry.Transport.PeerConnected += delegate(int id)
				{
					this.PeerConnected?.Invoke(id + captured.Offset);
				};
				entry.Transport.PeerDisconnected += delegate(int id, string r)
				{
					this.PeerDisconnected?.Invoke(id + captured.Offset, r);
				};
				entry.Transport.PacketReceived += delegate(int id, byte[] data)
				{
					this.PacketReceived?.Invoke(id + captured.Offset, data);
				};
			}
		}

		public void StartListening(int port, string connectionKey)
		{
		}

		public void Stop()
		{
			Entry[] entries = _entries;
			foreach (Entry entry in entries)
			{
				entry.Transport.Stop();
			}
		}

		public void Poll()
		{
			Entry[] entries = _entries;
			foreach (Entry entry in entries)
			{
				entry.Transport.Poll();
			}
		}

		public void Send(int peerId, byte[] payload, PacketDelivery delivery)
		{
			var (serverTransport, peerId2) = Resolve(peerId);
			serverTransport?.Send(peerId2, payload, delivery);
		}

		public void Broadcast(byte[] payload, PacketDelivery delivery, int excludePeerId = -1)
		{
			Entry[] entries = _entries;
			foreach (Entry entry in entries)
			{
				int excludePeerId2 = ((excludePeerId >= entry.Offset && excludePeerId < entry.Offset + 100000) ? (excludePeerId - entry.Offset) : (-1));
				entry.Transport.Broadcast(payload, delivery, excludePeerId2);
			}
		}

		public void Kick(int peerId, string reason = "")
		{
			var (serverTransport, peerId2) = Resolve(peerId);
			serverTransport?.Kick(peerId2, reason);
		}

		private (IServerTransport? Transport, int LocalId) Resolve(int peerId)
		{
			Entry[] entries = _entries;
			foreach (Entry entry in entries)
			{
				if (peerId >= entry.Offset && peerId < entry.Offset + 100000)
				{
					return (entry.Transport, peerId - entry.Offset);
				}
			}
			return (null, 0);
		}
	}
	public interface IClientTransport
	{
		bool IsConnected { get; }

		string TransportName { get; }

		event Action? Connected;

		event Action<string>? Disconnected;

		event Action<byte[]>? PacketReceived;

		void Connect(string address, int port, string connectionKey);

		void Disconnect();

		void Poll();

		void Send(byte[] payload, PacketDelivery delivery);
	}
	public interface IServerTransport
	{
		IEnumerable<int> ConnectedPeerIds { get; }

		bool IsRunning { get; }

		string TransportName { get; }

		event Action<int>? PeerConnected;

		event Action<int, string>? PeerDisconnected;

		event Action<int, byte[]>? PacketReceived;

		void StartListening(int port, string connectionKey);

		void Stop();

		void Poll();

		void Send(int peerId, byte[] payload, PacketDelivery delivery);

		void Broadcast(byte[] payload, PacketDelivery delivery, int excludePeerId = -1);

		void Kick(int peerId, string reason = "");
	}
	public enum PacketDelivery
	{
		Unreliable,
		Reliable,
		ReliableOrdered
	}
}
namespace BabyStepsNetworking.Transport.Steam
{
	public abstract class SteamClientTransport : IClientTransport
	{
		public abstract bool IsConnected { get; }

		public string TransportName => "Steam P2P";

		public abstract event Action? Connected;

		public abstract event Action<string>? Disconnected;

		public abstract event Action<byte[]>? PacketReceived;

		public abstract void Connect(string address, int port, string connectionKey);

		public abstract void Disconnect();

		public abstract void Poll();

		public abstract void Send(byte[] payload, PacketDelivery delivery);
	}
	public abstract class SteamServerTransport : IServerTransport
	{
		public abstract IEnumerable<int> ConnectedPeerIds { get; }

		public abstract bool IsRunning { get; }

		public string TransportName => "Steam P2P";

		public abstract event Action<int>? PeerConnected;

		public abstract event Action<int, string>? PeerDisconnected;

		public abstract event Action<int, byte[]>? PacketReceived;

		public event Action<string>? LobbyCreated;

		public abstract void StartListening(int port, string connectionKey);

		public abstract void Stop();

		public abstract void Poll();

		public abstract void Send(int peerId, byte[] payload, PacketDelivery delivery);

		public abstract void Broadcast(byte[] payload, PacketDelivery delivery, int excludePeerId = -1);

		public abstract void Kick(int peerId, string reason = "");

		protected void OnLobbyCreated(string lobbyId)
		{
			this.LobbyCreated?.Invoke(lobbyId);
		}
	}
}
namespace BabyStepsNetworking.Transport.LocalLoopback
{
	public static class LocalLoopbackTransportPair
	{
		public static (LocalLoopbackServerTransport Server, LocalLoopbackClientTransport Client) Create()
		{
			Queue<byte[]> queue = new Queue<byte[]>();
			Queue<byte[]> queue2 = new Queue<byte[]>();
			LocalLoopbackServerTransport item = new LocalLoopbackServerTransport(queue2, queue);
			LocalLoopbackClientTransport item2 = new LocalLoopbackClientTransport(queue, queue2);
			return (item, item2);
		}
	}
	public sealed class LocalLoopbackServerTransport : IServerTransport
	{
		private readonly Queue<byte[]> _incoming;

		private readonly Queue<byte[]> _outgoing;

		private bool _clientConnected = false;

		private bool _running = false;

		public IEnumerable<int> ConnectedPeerIds => _clientConnected ? ((IEnumerable<int>)new int[1]) : ((IEnumerable<int>)Array.Empty<int>());

		public bool IsRunning => _running;

		public string TransportName => "Loopback";

		public event Action<int>? PeerConnected;

		public event Action<int, string>? PeerDisconnected;

		public event Action<int, byte[]>? PacketReceived;

		internal LocalLoopbackServerTransport(Queue<byte[]> incoming, Queue<byte[]> outgoing)
		{
			_incoming = incoming;
			_outgoing = outgoing;
		}

		public void StartListening(int port, string connectionKey)
		{
			_running = true;
		}

		public void Stop()
		{
			if (_running)
			{
				_running = false;
				if (_clientConnected)
				{
					_clientConnected = false;
					this.PeerDisconnected?.Invoke(0, "Server stopped");
				}
			}
		}

		public void Poll()
		{
			if (!_running)
			{
				return;
			}
			if (!_clientConnected && _incoming.Count > 0 && _incoming.Peek() == null)
			{
				_incoming.Dequeue();
				_clientConnected = true;
				this.PeerConnected?.Invoke(0);
				return;
			}
			while (_clientConnected && _incoming.Count > 0)
			{
				byte[] array = _incoming.Dequeue();
				if (array == null)
				{
					_clientConnected = false;
					this.PeerDisconnected?.Invoke(0, "Client disconnected");
					break;
				}
				this.PacketReceived?.Invoke(0, array);
			}
		}

		public void Send(int peerId, byte[] payload, PacketDelivery delivery)
		{
			if (_clientConnected && peerId == 0)
			{
				_outgoing.Enqueue(payload);
			}
		}

		public void Broadcast(byte[] payload, PacketDelivery delivery, int excludePeerId = -1)
		{
			if (_clientConnected && excludePeerId != 0)
			{
				_outgoing.Enqueue(payload);
			}
		}

		public void Kick(int peerId, string reason = "")
		{
			if (_clientConnected && peerId == 0)
			{
				_outgoing.Enqueue(null);
				_clientConnected = false;
				this.PeerDisconnected?.Invoke(0, reason);
			}
		}

		internal void SignalClientConnect()
		{
			_incoming.Enqueue(null);
		}

		internal void SignalClientDisconnect()
		{
			_incoming.Enqueue(null);
		}
	}
	public sealed class LocalLoopbackClientTransport : IClientTransport
	{
		private readonly Queue<byte[]> _incoming;

		private readonly Queue<byte[]> _outgoing;

		internal LocalLoopbackServerTransport? ServerSide;

		private bool _connected = false;

		public bool IsConnected => _connected;

		public string TransportName => "Loopback";

		public event Action? Connected;

		public event Action<string>? Disconnected;

		public event Action<byte[]>? PacketReceived;

		internal LocalLoopbackClientTransport(Queue<byte[]> incoming, Queue<byte[]> outgoing)
		{
			_incoming = incoming;
			_outgoing = outgoing;
		}

		public void Connect(string address, int port, string connectionKey)
		{
			if (!_connected)
			{
				_connected = true;
				_outgoing.Enqueue(null);
				this.Connected?.Invoke();
			}
		}

		public void Disconnect()
		{
			if (_connected)
			{
				_connected = false;
				_outgoing.Enqueue(null);
				this.Disconnected?.Invoke("Disconnected");
			}
		}

		public void Poll()
		{
			if (!_connected)
			{
				return;
			}
			while (_incoming.Count > 0)
			{
				byte[] array = _incoming.Dequeue();
				if (array == null)
				{
					_connected = false;
					this.Disconnected?.Invoke("Server disconnected");
					break;
				}
				this.PacketReceived?.Invoke(array);
			}
		}

		public void Send(byte[] payload, PacketDelivery delivery)
		{
			if (_connected)
			{
				_outgoing.Enqueue(payload);
			}
		}
	}
}
namespace BabyStepsNetworking.Transport.LiteNetLib
{
	public sealed class LiteNetLibClientTransport : IClientTransport, INetEventListener
	{
		private NetManager? _netManager;

		private NetPeer? _server;

		private readonly NetDataWriter _writer = new NetDataWriter();

		public bool IsConnected => _server != null;

		public string TransportName => "LiteNetLib";

		public event Action? Connected;

		public event Action<string>? Disconnected;

		public event Action<byte[]>? PacketReceived;

		public void Connect(string address, int port, string connectionKey)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			NetManager? netManager = _netManager;
			if (netManager != null)
			{
				netManager.Stop();
			}
			_netManager = new NetManager((INetEventListener)(object)this, (PacketLayerBase)null)
			{
				AutoRecycle = true,
				DisconnectTimeout = 15000
			};
			_netManager.Start();
			_netManager.Connect(address, port, connectionKey);
		}

		public void Disconnect()
		{
			NetManager? netManager = _netManager;
			if (netManager != null)
			{
				netManager.Stop();
			}
			_netManager = null;
			_server = null;
		}

		public void Poll()
		{
			if (_netManager != null && !_netManager.UnsyncedEvents)
			{
				_netManager.PollEvents(0);
			}
		}

		public void Send(byte[] payload, PacketDelivery delivery)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			if (_server == null)
			{
				return;
			}
			lock (_writer)
			{
				_writer.Reset();
				_writer.Put((ushort)(payload.Length + 2));
				_writer.Put(payload);
				_server.Send(_writer, ToLnl(delivery));
			}
		}

		void INetEventListener.OnPeerConnected(NetPeer peer)
		{
			_server = peer;
			this.Connected?.Invoke();
		}

		void INetEventListener.OnPeerDisconnected(NetPeer peer, DisconnectInfo info)
		{
			_server = null;
			this.Disconnected?.Invoke(((object)(DisconnectReason)(ref info.Reason)).ToString());
		}

		void INetEventListener.OnConnectionRequest(ConnectionRequest request)
		{
			request.AcceptIfKey("cuzzillobochfoddy");
		}

		void INetEventListener.OnNetworkReceive(NetPeer peer, NetPacketReader reader, byte channelNumber, DeliveryMethod deliveryMethod)
		{
			ReadPacket(reader);
		}

		void INetEventListener.OnNetworkReceiveUnconnected(IPEndPoint ep, NetPacketReader reader, UnconnectedMessageType type)
		{
			ReadPacket(reader);
		}

		private void ReadPacket(NetPacketReader reader)
		{
			byte[] remainingBytes = ((NetDataReader)reader).GetRemainingBytes();
			reader.Recycle();
			if (remainingBytes.Length >= 2)
			{
				ushort num = BitConverter.ToUInt16(remainingBytes, 0);
				if (num == remainingBytes.Length)
				{
					byte[] array = new byte[remainingBytes.Length - 2];
					Buffer.BlockCopy(remainingBytes, 2, array, 0, array.Length);
					this.PacketReceived?.Invoke(array);
				}
			}
		}

		void INetEventListener.OnNetworkError(IPEndPoint ep, SocketError err)
		{
		}

		void INetEventListener.OnNetworkLatencyUpdate(NetPeer peer, int latency)
		{
		}

		private static DeliveryMethod ToLnl(PacketDelivery d)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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)
			if (1 == 0)
			{
			}
			DeliveryMethod result = ((d != PacketDelivery.ReliableOrdered) ? ((DeliveryMethod)0) : ((DeliveryMethod)2));
			if (1 == 0)
			{
			}
			return result;
		}
	}
	public sealed class LiteNetLibServerTransport : IServerTransport, INetEventListener
	{
		private readonly NetManager _netManager;

		private readonly NetDataWriter _writer = new NetDataWriter();

		private string _connectionKey = string.Empty;

		private readonly Dictionary<int, NetPeer> _peers = new Dictionary<int, NetPeer>();

		public IEnumerable<int> ConnectedPeerIds => _peers.Keys;

		public bool IsRunning => _netManager.IsRunning;

		public string TransportName => "LiteNetLib";

		public event Action<int>? PeerConnected;

		public event Action<int, string>? PeerDisconnected;

		public event Action<int, byte[]>? PacketReceived;

		public LiteNetLibServerTransport()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Expected O, but got Unknown
			_netManager = new NetManager((INetEventListener)(object)this, (PacketLayerBase)null)
			{
				AutoRecycle = true,
				IPv6Enabled = false,
				DisconnectTimeout = 15000
			};
		}

		public void StartListening(int port, string connectionKey)
		{
			_connectionKey = connectionKey;
			_netManager.Start(port);
		}

		public void Stop()
		{
			_netManager.Stop();
		}

		public void Poll()
		{
			_netManager.PollEvents(0);
		}

		public void Send(int peerId, byte[] payload, PacketDelivery delivery)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			if (!_peers.TryGetValue(peerId, out NetPeer value))
			{
				return;
			}
			lock (_writer)
			{
				_writer.Reset();
				_writer.Put((ushort)(payload.Length + 2));
				_writer.Put(payload);
				value.Send(_writer, ToLnl(delivery));
			}
		}

		public void Broadcast(byte[] payload, PacketDelivery delivery, int excludePeerId = -1)
		{
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			lock (_writer)
			{
				_writer.Reset();
				_writer.Put((ushort)(payload.Length + 2));
				_writer.Put(payload);
				foreach (var (num2, val2) in _peers)
				{
					if (num2 != excludePeerId)
					{
						val2.Send(_writer, ToLnl(delivery));
					}
				}
			}
		}

		public void Kick(int peerId, string reason = "")
		{
			if (_peers.TryGetValue(peerId, out NetPeer value))
			{
				value.Disconnect();
			}
		}

		void INetEventListener.OnConnectionRequest(ConnectionRequest request)
		{
			string text = default(string);
			if (request.Data.TryGetString(ref text) && text == _connectionKey)
			{
				request.Accept();
			}
			else
			{
				request.Reject();
			}
		}

		void INetEventListener.OnPeerConnected(NetPeer peer)
		{
			_peers[peer.Id] = peer;
			this.PeerConnected?.Invoke(peer.Id);
		}

		void INetEventListener.OnPeerDisconnected(NetPeer peer, DisconnectInfo info)
		{
			_peers.Remove(peer.Id);
			this.PeerDisconnected?.Invoke(peer.Id, ((object)(DisconnectReason)(ref info.Reason)).ToString());
		}

		void INetEventListener.OnNetworkReceive(NetPeer peer, NetPacketReader reader, byte channelNumber, DeliveryMethod deliveryMethod)
		{
			byte[] remainingBytes = ((NetDataReader)reader).GetRemainingBytes();
			reader.Recycle();
			if (remainingBytes.Length >= 2)
			{
				ushort num = BitConverter.ToUInt16(remainingBytes, 0);
				if (num == remainingBytes.Length)
				{
					byte[] array = new byte[remainingBytes.Length - 2];
					Buffer.BlockCopy(remainingBytes, 2, array, 0, array.Length);
					this.PacketReceived?.Invoke(peer.Id, array);
				}
			}
		}

		void INetEventListener.OnNetworkError(IPEndPoint ep, SocketError err)
		{
		}

		void INetEventListener.OnNetworkLatencyUpdate(NetPeer peer, int latency)
		{
		}

		void INetEventListener.OnNetworkReceiveUnconnected(IPEndPoint ep, NetPacketReader reader, UnconnectedMessageType type)
		{
			reader.Recycle();
		}

		private static DeliveryMethod ToLnl(PacketDelivery d)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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)
			if (1 == 0)
			{
			}
			DeliveryMethod result = ((d != PacketDelivery.ReliableOrdered) ? ((DeliveryMethod)0) : ((DeliveryMethod)2));
			if (1 == 0)
			{
			}
			return result;
		}
	}
}
namespace BabyStepsNetworking.Shared
{
	public struct RGBColor
	{
		public byte R;

		public byte G;

		public byte B;

		public RGBColor(byte r, byte g, byte b)
		{
			R = r;
			G = g;
			B = b;
		}

		public string GetString()
		{
			return $"[{R},{G},{B}]";
		}
	}
}
namespace BabyStepsNetworking.ServerBrowser
{
	public interface IServerBrowserSource
	{
		string SourceName { get; }

		event Action<IReadOnlyList<ServerInfo>>? ServersFound;

		void Refresh();
	}
	public sealed class LanServerBrowserSource : IServerBrowserSource
	{
		public string SourceName => "LAN";

		public event Action<IReadOnlyList<ServerInfo>>? ServersFound;

		public void Refresh()
		{
			this.ServersFound?.Invoke(Array.Empty<ServerInfo>());
		}
	}
	public enum ServerType
	{
		LiteNetLib,
		SteamP2P
	}
	public sealed class ServerInfo
	{
		public string Name { get; set; } = string.Empty;


		public string Address { get; set; } = string.Empty;


		public int Port { get; set; }

		public int PlayerCount { get; set; }

		public int MaxPlayers { get; set; } = 255;


		public bool IsPasswordProtected { get; set; }

		public ServerType Type { get; set; } = ServerType.LiteNetLib;


		public int PingMs { get; set; } = -1;


		public string? SessionId { get; set; }

		public override string ToString()
		{
			return $"[{Type}] {Name} ({Address}:{Port}) {PlayerCount}/{MaxPlayers} {PingMs}ms";
		}
	}
	public abstract class SteamLobbyBrowserSource : IServerBrowserSource
	{
		public string SourceName => "Steam Lobbies";

		public abstract event Action<IReadOnlyList<ServerInfo>>? ServersFound;

		public abstract void Refresh();
	}
}
namespace BabyStepsNetworking.Packets
{
	public sealed class ClientPacketRegistry
	{
		public delegate void ClientPacketHandler(byte[] data, NetworkClient client);

		private const byte ModRangeStart = 65;

		private const byte ModRangeEnd = 254;

		private readonly Dictionary<byte, ClientPacketHandler> _handlers = new Dictionary<byte, ClientPacketHandler>();

		private byte _nextModOpcode = 65;

		public void RegisterCoreHandler(byte opcode, ClientPacketHandler handler)
		{
			_handlers[opcode] = handler;
		}

		public void RegisterCoreHandler(CoreServerToClientOpcode opcode, ClientPacketHandler handler)
		{
			RegisterCoreHandler((byte)opcode, handler);
		}

		public byte AllocateModOpcode(ClientPacketHandler handler)
		{
			if (_nextModOpcode > 254)
			{
				return 0;
			}
			byte b = _nextModOpcode++;
			_handlers[b] = handler;
			return b;
		}

		public void Dispatch(byte opcode, byte[] data, NetworkClient client)
		{
			if (_handlers.TryGetValue(opcode, out ClientPacketHandler value))
			{
				value(data, client);
			}
		}
	}
	public enum CoreClientToServerOpcode : byte
	{
		BoneUpdate = 1,
		PlayerInfo = 2,
		WorldEvent = 3,
		AccessoryAdd = 4,
		AccessoryRemove = 5,
		JiminyRibbon = 6,
		CollisionToggle = 7,
		ChatMessage = 8,
		AudioFrame = 9,
		Ping = 10,
		RequestState = 11,
		ModRangeStart = 65,
		ModRangeEnd = 254
	}
	public enum CoreServerToClientOpcode : byte
	{
		AssignUUID = 1,
		PlayerJoined = 2,
		PlayerLeft = 3,
		PlayerInfoUpdate = 4,
		BoneUpdate = 5,
		WorldEvent = 6,
		AccessoryAdd = 7,
		AccessoryRemove = 8,
		JiminyRibbon = 9,
		CollisionToggle = 10,
		ChatMessage = 11,
		AudioFrame = 12,
		ModRangeStart = 65,
		ModRangeEnd = 254
	}
	public static class PacketBuilder
	{
		public static byte[] Build(byte opcode)
		{
			return new byte[1] { opcode };
		}

		public static byte[] Build(byte opcode, byte[] payload)
		{
			byte[] array = new byte[1 + payload.Length];
			array[0] = opcode;
			Buffer.BlockCopy(payload, 0, array, 1, payload.Length);
			return array;
		}

		public static byte[] Build(byte opcode, Action<List<byte>> buildPayload)
		{
			List<byte> list = new List<byte> { opcode };
			buildPayload(list);
			return list.ToArray();
		}

		public static byte[] Build(CoreServerToClientOpcode opcode)
		{
			return Build((byte)opcode);
		}

		public static byte[] Build(CoreServerToClientOpcode opcode, byte[] payload)
		{
			return Build((byte)opcode, payload);
		}

		public static byte[] Build(CoreServerToClientOpcode opcode, Action<List<byte>> buildPayload)
		{
			return Build((byte)opcode, buildPayload);
		}

		public static byte[] Build(CoreClientToServerOpcode opcode)
		{
			return Build((byte)opcode);
		}

		public static byte[] Build(CoreClientToServerOpcode opcode, byte[] payload)
		{
			return Build((byte)opcode, payload);
		}

		public static byte[] Build(CoreClientToServerOpcode opcode, Action<List<byte>> buildPayload)
		{
			return Build((byte)opcode, buildPayload);
		}

		public static byte[] PrependUuid(byte uuid, byte[] payload)
		{
			byte[] array = new byte[1 + payload.Length];
			array[0] = uuid;
			Buffer.BlockCopy(payload, 0, array, 1, payload.Length);
			return array;
		}
	}
	public static class PacketReader
	{
		public static bool TryRead(byte[] raw, out byte opcode, out byte[] payload)
		{
			if (raw.Length < 1)
			{
				opcode = 0;
				payload = Array.Empty<byte>();
				return false;
			}
			opcode = raw[0];
			payload = new byte[raw.Length - 1];
			if (payload.Length != 0)
			{
				Buffer.BlockCopy(raw, 1, payload, 0, payload.Length);
			}
			return true;
		}

		public static ushort ReadU16(byte[] data, int offset)
		{
			return BitConverter.ToUInt16(data, offset);
		}

		public static long ReadI64(byte[] data, int offset)
		{
			return BitConverter.ToInt64(data, offset);
		}
	}
	public sealed class ServerPacketRegistry
	{
		public delegate void ServerPacketHandler(ConnectedClient sender, byte[] data, NetworkHost host);

		private const byte ModRangeStart = 65;

		private const byte ModRangeEnd = 254;

		private readonly Dictionary<byte, ServerPacketHandler> _handlers = new Dictionary<byte, ServerPacketHandler>();

		private byte _nextModOpcode = 65;

		public void RegisterCoreHandler(byte opcode, ServerPacketHandler handler)
		{
			_handlers[opcode] = handler;
		}

		public void RegisterCoreHandler(CoreClientToServerOpcode opcode, ServerPacketHandler handler)
		{
			RegisterCoreHandler((byte)opcode, handler);
		}

		public byte AllocateModOpcode(ServerPacketHandler handler)
		{
			if (_nextModOpcode > 254)
			{
				return 0;
			}
			byte b = _nextModOpcode++;
			_handlers[b] = handler;
			return b;
		}

		public void Dispatch(ConnectedClient sender, byte opcode, byte[] data, NetworkHost host)
		{
			ConnectedClient sender2 = sender;
			byte[] data2 = data;
			if (_handlers.TryGetValue(opcode, out ServerPacketHandler value))
			{
				value(sender2, data2, host);
			}
			else if (opcode >= 65 && opcode <= 254)
			{
				byte[] packet = PacketBuilder.Build(opcode, delegate(List<byte> bytes)
				{
					bytes.Add(sender2.Uuid);
					bytes.AddRange(data2);
				});
				host.Broadcast(packet, PacketDelivery.Reliable, sender2.PeerId);
			}
		}
	}
}
namespace BabyStepsNetworking.Host
{
	public sealed class ConnectedClient
	{
		public int PeerId { get; init; }

		public byte Uuid { get; init; }

		public string? DisplayName { get; set; }

		public RGBColor? Color { get; set; }

		public bool CollisionsEnabled { get; set; } = false;


		public bool JiminyState { get; set; } = false;


		public byte LastBoneKickoffPoint { get; set; } = 0;


		public byte[]? LatestRawBoneData { get; set; }

		public Vector3 Position { get; set; }

		public List<int>? DistantClientPeerIds { get; set; }

		public Dictionary<int, long> LastTransmitTimes { get; } = new Dictionary<int, long>();


		public byte[]? InfoPacket { get; set; }

		public Dictionary<byte, byte[]?> SavedPackets { get; } = new Dictionary<byte, byte[]>();


		public bool IsInitialized => DisplayName != null && Color.HasValue;
	}
	public class HostSettings
	{
		public int Port { get; set; } = 7777;


		public string Password { get; set; } = "cuzzillobochfoddy";


		public float DistanceCutoff { get; set; } = 10f;


		public float OuterDistanceCutoff { get; set; } = 500f;


		public float CullIntervalMs { get; set; } = 1000f;


		public float MaxBandwidthKbps { get; set; } = 512f;


		public bool TelemetryEnabled { get; set; } = false;


		public float TelemetryIntervalMs { get; set; } = 5000f;


		public bool VoiceChatEnabled { get; set; } = true;


		public string ServerVersion { get; set; } = "106";


		public string ConnectionKey => ServerVersion + Password;
	}
	public sealed class NetworkHost
	{
		private readonly IServerTransport _transport;

		private readonly HostSettings _settings;

		private readonly ServerPacketRegistry _registry;

		private readonly BandwidthManager _bandwidth;

		private readonly Dictionary<int, ConnectedClient> _peerToClient = new Dictionary<int, ConnectedClient>();

		private readonly Dictionary<byte, ConnectedClient> _uuidToClient = new Dictionary<byte, ConnectedClient>();

		private readonly HashSet<byte> _usedUuids = new HashSet<byte>();

		private readonly Dictionary<byte, ushort> _lastSeenSequence = new Dictionary<byte, ushort>();

		private const byte MaxUuid = 254;

		private readonly Stopwatch _uptime = new Stopwatch();

		private volatile bool _isCulling;

		private readonly object _cullLock = new object();

		private float _timeSinceCullMs;

		private readonly int _targetFps;

		public long UptimeMs => _uptime.ElapsedMilliseconds;

		public bool IsRunning => _transport.IsRunning;

		public IReadOnlyDictionary<byte, ConnectedClient> Clients => _uuidToClient;

		public event Action<ConnectedClient>? ClientConnected;

		public event Action<ConnectedClient>? ClientDisconnected;

		public event Action<string>? Log;

		public NetworkHost(IServerTransport transport, HostSettings settings, int targetFps = 60)
		{
			_transport = transport;
			_settings = settings;
			_targetFps = targetFps;
			_registry = new ServerPacketRegistry();
			_bandwidth = new BandwidthManager(transport, settings, targetFps, _peerToClient);
			transport.PeerConnected += OnPeerConnected;
			transport.PeerDisconnected += OnPeerDisconnected;
			transport.PacketReceived += OnPacketReceived;
		}

		public void RegisterHandler(byte opcode, ServerPacketRegistry.ServerPacketHandler handler)
		{
			_registry.RegisterCoreHandler(opcode, handler);
		}

		public void RegisterHandler(CoreClientToServerOpcode opcode, ServerPacketRegistry.ServerPacketHandler handler)
		{
			_registry.RegisterCoreHandler(opcode, handler);
		}

		public byte AllocateModOpcode(ServerPacketRegistry.ServerPacketHandler handler)
		{
			return _registry.AllocateModOpcode(handler);
		}

		public void Start()
		{
			_transport.StartListening(_settings.Port, _settings.ConnectionKey);
			_uptime.Restart();
			this.Log?.Invoke($"Server listening on port {_settings.Port} [{_transport.TransportName}]");
		}

		public void StartWithoutListening()
		{
			_uptime.Restart();
			this.Log?.Invoke("Server started [" + _transport.TransportName + "]");
		}

		public void Stop()
		{
			_transport.Stop();
		}

		public void Tick(float deltaMs)
		{
			_transport.Poll();
			_bandwidth.ProcessQueues();
			_timeSinceCullMs += deltaMs;
			if (_timeSinceCullMs >= _settings.CullIntervalMs && !_isCulling)
			{
				_timeSinceCullMs = 0f;
				_isCulling = true;
				Task.Run((Action)CullDistantClients);
			}
		}

		public void Send(int peerId, byte[] packet, PacketDelivery delivery)
		{
			_transport.Send(peerId, packet, delivery);
		}

		public void Broadcast(byte[] packet, PacketDelivery delivery, int excludePeerId = -1)
		{
			_transport.Broadcast(packet, delivery, excludePeerId);
		}

		public void EnqueueBoneUpdate(int senderPeerId, byte[] packet)
		{
			_bandwidth.EnqueueBoneUpdate(senderPeerId, packet);
		}

		public void EnqueueAudio(int senderPeerId, byte[] packet)
		{
			_bandwidth.EnqueueAudioFrame(senderPeerId, packet);
		}

		public void EnqueueHighPriority(int senderPeerId, byte[] packet)
		{
			_bandwidth.EnqueueHighPriority(senderPeerId, packet);
		}

		public void BroadcastModPacket(byte opcode, byte senderUuid, byte[] payload, PacketDelivery delivery, int excludePeerId = -1)
		{
			byte[] payload2 = payload;
			byte[] payload3 = PacketBuilder.Build(opcode, delegate(List<byte> bytes)
			{
				bytes.Add(senderUuid);
				bytes.AddRange(payload2);
			});
			_transport.Broadcast(payload3, delivery, excludePeerId);
		}

		public bool IsNewerSequence(byte uuid, ushort seq)
		{
			if (!_lastSeenSequence.TryGetValue(uuid, out var value) || IsNewer(seq, value))
			{
				_lastSeenSequence[uuid] = seq;
				return true;
			}
			return false;
		}

		private static bool IsNewer(ushort current, ushort previous)
		{
			return (ushort)(current - previous) < 32768;
		}

		private void OnPeerConnected(int peerId)
		{
			byte uuid = AllocateUuid();
			if (uuid == byte.MaxValue)
			{
				_transport.Kick(peerId, "Server full");
				this.Log?.Invoke("Client rejected: server full");
				return;
			}
			ConnectedClient connectedClient = new ConnectedClient
			{
				PeerId = peerId,
				Uuid = uuid
			};
			_peerToClient[peerId] = connectedClient;
			_uuidToClient[uuid] = connectedClient;
			byte[] payload = PacketBuilder.Build(CoreServerToClientOpcode.AssignUUID, delegate(List<byte> bytes)
			{
				bytes.Add(uuid);
				bytes.AddRange(BitConverter.GetBytes(UptimeMs));
			});
			_transport.Send(peerId, payload, PacketDelivery.ReliableOrdered);
			foreach (ConnectedClient value in _uuidToClient.Values)
			{
				if (value.PeerId == peerId || value.InfoPacket == null)
				{
					continue;
				}
				_transport.Send(peerId, PacketBuilder.Build(CoreServerToClientOpcode.PlayerJoined, new byte[1] { value.Uuid }), PacketDelivery.ReliableOrdered);
				_transport.Send(peerId, value.InfoPacket, PacketDelivery.ReliableOrdered);
				foreach (byte[] value2 in value.SavedPackets.Values)
				{
					if (value2 != null)
					{
						_transport.Send(peerId, value2, PacketDelivery.ReliableOrdered);
					}
				}
			}
			this.ClientConnected?.Invoke(connectedClient);
		}

		private void OnPeerDisconnected(int peerId, string reason)
		{
			if (_peerToClient.TryGetValue(peerId, out ConnectedClient value))
			{
				_peerToClient.Remove(peerId);
				_uuidToClient.Remove(value.Uuid);
				_lastSeenSequence.Remove(value.Uuid);
				ReclaimUuid(value.Uuid);
				byte[] payload = PacketBuilder.Build(CoreServerToClientOpcode.PlayerLeft, new byte[1] { value.Uuid });
				_transport.Broadcast(payload, PacketDelivery.ReliableOrdered, peerId);
				this.Log?.Invoke(string.Format("Player {0}[{1}] disconnected: {2}", value.DisplayName ?? "?", value.Uuid, reason));
				this.ClientDisconnected?.Invoke(value);
			}
		}

		private void OnPacketReceived(int peerId, byte[] payload)
		{
			if (_peerToClient.TryGetValue(peerId, out ConnectedClient value) && payload.Length >= 1)
			{
				byte opcode = payload[0];
				byte[] subArray = payload[1..];
				_registry.Dispatch(value, opcode, subArray, this);
			}
		}

		private byte AllocateUuid()
		{
			for (byte b = 0; b <= 254; b++)
			{
				if (!_usedUuids.Contains(b))
				{
					_usedUuids.Add(b);
					return b;
				}
			}
			this.Log?.Invoke("Maximum number of clients reached!");
			return byte.MaxValue;
		}

		private void ReclaimUuid(byte uuid)
		{
			_usedUuids.Remove(uuid);
		}

		private void CullDistantClients()
		{
			lock (_cullLock)
			{
				foreach (ConnectedClient value in _peerToClient.Values)
				{
					byte[] latestRawBoneData = value.LatestRawBoneData;
					if (latestRawBoneData != null && latestRawBoneData.Length >= 12)
					{
						float z = BitConverter.ToSingle(latestRawBoneData, 8);
						value.Position = new Vector3(0f, 0f, z);
					}
				}
				foreach (ConnectedClient value2 in _peerToClient.Values)
				{
					List<int> list = new List<int>();
					if (value2.LatestRawBoneData == null)
					{
						value2.DistantClientPeerIds = list;
						continue;
					}
					foreach (ConnectedClient value3 in _peerToClient.Values)
					{
						if (value2.PeerId != value3.PeerId && value3.LatestRawBoneData != null)
						{
							float num = Math.Abs(value2.Position.Z - value3.Position.Z);
							if (num > _settings.DistanceCutoff)
							{
								list.Add(value3.PeerId);
							}
						}
					}
					value2.DistantClientPeerIds = list;
				}
			}
			_isCulling = false;
		}
	}
}
namespace BabyStepsNetworking.Extensions
{
	public interface IModChannel
	{
		string ModId { get; }

		byte Opcode { get; }

		event Action<byte, byte[]>? DataReceived;

		void Send(byte[] payload, PacketDelivery delivery = PacketDelivery.Reliable);
	}
	public interface INetworkExtension
	{
		string ExtensionId { get; }

		void Initialize(NetworkExtensionContext ctx);
	}
	public sealed class NetworkExtensionContext
	{
		private readonly NetworkClient _client;

		public NetworkHost? Host { get; }

		public bool IsHosting => Host != null;

		internal NetworkExtensionContext(NetworkClient client, NetworkHost? host)
		{
			_client = client;
			Host = host;
		}

		public IModChannel? CreateChannel()
		{
			return _client.CreateModChannel("ext");
		}
	}
}
namespace BabyStepsNetworking.Client
{
	internal sealed class ModChannel : IModChannel
	{
		private readonly NetworkClient _client;

		public string ModId { get; }

		public byte Opcode { get; internal set; }

		public event Action<byte, byte[]>? DataReceived;

		internal ModChannel(string modId, NetworkClient client)
		{
			ModId = modId;
			_client = client;
		}

		public void Send(byte[] payload, PacketDelivery delivery = PacketDelivery.Reliable)
		{
			_client.Send(PacketBuilder.Build(Opcode, payload), delivery);
		}

		internal void DispatchReceived(byte[] data)
		{
			if (data.Length >= 1)
			{
				byte arg = data[0];
				byte[] array = new byte[data.Length - 1];
				if (array.Length != 0)
				{
					Buffer.BlockCopy(data, 1, array, 0, array.Length);
				}
				this.DataReceived?.Invoke(arg, array);
			}
		}
	}
	public sealed class NetworkClient
	{
		private readonly IClientTransport _transport;

		private readonly ClientPacketRegistry _registry;

		public bool IsConnected => _transport.IsConnected;

		public string TransportName => _transport.TransportName;

		public IClientTransport Transport => _transport;

		public event Action? Connected;

		public event Action<string>? Disconnected;

		public NetworkClient(IClientTransport transport)
		{
			_transport = transport;
			_registry = new ClientPacketRegistry();
			transport.Connected += delegate
			{
				this.Connected?.Invoke();
			};
			transport.Disconnected += delegate(string reason)
			{
				this.Disconnected?.Invoke(reason);
			};
			transport.PacketReceived += OnPacketReceived;
		}

		public void RegisterHandler(byte opcode, ClientPacketRegistry.ClientPacketHandler handler)
		{
			_registry.RegisterCoreHandler(opcode, handler);
		}

		public void RegisterHandler(CoreServerToClientOpcode opcode, ClientPacketRegistry.ClientPacketHandler handler)
		{
			_registry.RegisterCoreHandler(opcode, handler);
		}

		public void Connect(string address, int port, string connectionKey)
		{
			_transport.Connect(address, port, connectionKey);
		}

		public void Disconnect()
		{
			_transport.Disconnect();
		}

		public void Tick()
		{
			_transport.Poll();
		}

		public void Send(byte[] packet, PacketDelivery delivery)
		{
			_transport.Send(packet, delivery);
		}

		public void Send(byte opcode, byte[] payload, PacketDelivery delivery = PacketDelivery.Reliable)
		{
			_transport.Send(PacketBuilder.Build(opcode, payload), delivery);
		}

		public void Send(CoreClientToServerOpcode opcode, byte[] payload, PacketDelivery delivery = PacketDelivery.Reliable)
		{
			Send((byte)opcode, payload, delivery);
		}

		public IModChannel? CreateModChannel(string modId)
		{
			ModChannel channel = new ModChannel(modId, this);
			byte b = _registry.AllocateModOpcode(delegate(byte[] data, NetworkClient _)
			{
				channel.DispatchReceived(data);
			});
			if (b == 0)
			{
				return null;
			}
			channel.Opcode = b;
			return channel;
		}

		public void RegisterExtension(INetworkExtension extension, NetworkHost? host = null)
		{
			NetworkExtensionContext ctx = new NetworkExtensionContext(this, host);
			extension.Initialize(ctx);
		}

		private void OnPacketReceived(byte[] payload)
		{
			if (payload.Length >= 1)
			{
				byte opcode = payload[0];
				byte[] array = new byte[payload.Length - 1];
				if (array.Length != 0)
				{
					Buffer.BlockCopy(payload, 1, array, 0, array.Length);
				}
				_registry.Dispatch(opcode, array, this);
			}
		}

		internal byte AllocateModOpcode(ClientPacketRegistry.ClientPacketHandler handler)
		{
			return _registry.AllocateModOpcode(handler);
		}
	}
}
namespace BabyStepsNetworking.Bandwidth
{
	public sealed class BandwidthManager
	{
		private enum PacketPriority
		{
			High,
			Medium,
			Low
		}

		private sealed class QueuedPacket
		{
			public int FromPeerId;

			public byte[] Payload = Array.Empty<byte>();

			public PacketPriority Priority;

			public long QueuedTick;
		}

		private const float AUDIO_MAX_DISTANCE = 60f;

		private readonly Queue<QueuedPacket> _highQueue = new Queue<QueuedPacket>();

		private readonly Queue<QueuedPacket> _mediumQueue = new Queue<QueuedPacket>();

		private readonly Queue<QueuedPacket> _lowQueue = new Queue<QueuedPacket>();

		private readonly IServerTransport _transport;

		private readonly HostSettings _settings;

		private readonly int _targetFps;

		private readonly Dictionary<int, ConnectedClient> _clients;

		private long _bytesSentThisInterval;

		private long _lastTelemetryTick;

		private readonly Stopwatch _telemetryWatch = Stopwatch.StartNew();

		public int TotalQueued => _highQueue.Count + _mediumQueue.Count + _lowQueue.Count;

		public BandwidthManager(IServerTransport transport, HostSettings settings, int targetFps, Dictionary<int, ConnectedClient> clients)
		{
			_transport = transport;
			_settings = settings;
			_targetFps = targetFps;
			_clients = clients;
		}

		public void EnqueueBoneUpdate(int fromPeerId, byte[] payload)
		{
			_mediumQueue.Enqueue(new QueuedPacket
			{
				FromPeerId = fromPeerId,
				Payload = payload,
				Priority = PacketPriority.Medium,
				QueuedTick = Stopwatch.GetTimestamp()
			});
		}

		public void EnqueueAudioFrame(int fromPeerId, byte[] payload)
		{
			_lowQueue.Enqueue(new QueuedPacket
			{
				FromPeerId = fromPeerId,
				Payload = payload,
				Priority = PacketPriority.Low,
				QueuedTick = Stopwatch.GetTimestamp()
			});
		}

		public void EnqueueHighPriority(int fromPeerId, byte[] payload)
		{
			_highQueue.Enqueue(new QueuedPacket
			{
				FromPeerId = fromPeerId,
				Payload = payload,
				Priority = PacketPriority.High,
				QueuedTick = Stopwatch.GetTimestamp()
			});
		}

		public void ProcessQueues()
		{
			float num = _settings.MaxBandwidthKbps * 1024f / (float)_targetFps;
			int num2 = (int)num;
			long timestamp = Stopwatch.GetTimestamp();
			double msPerTick = 1000.0 / (double)Stopwatch.Frequency;
			float updateIntervalMs = 1000f / (float)_targetFps;
			int num3 = 0;
			while (_highQueue.Count > 0)
			{
				QueuedPacket queuedPacket = _highQueue.Dequeue();
				if (_clients.ContainsKey(queuedPacket.FromPeerId))
				{
					num3 += BroadcastToAll(queuedPacket, PacketDelivery.ReliableOrdered);
				}
			}
			while (_mediumQueue.Count > 0 && num3 < num2)
			{
				QueuedPacket queuedPacket2 = _mediumQueue.Dequeue();
				if (_clients.ContainsKey(queuedPacket2.FromPeerId))
				{
					num3 += BroadcastBoneUpdate(queuedPacket2, timestamp, msPerTick, updateIntervalMs);
				}
			}
			while (_lowQueue.Count > 0 && num3 < num2)
			{
				QueuedPacket queuedPacket3 = _lowQueue.Dequeue();
				if (_clients.ContainsKey(queuedPacket3.FromPeerId))
				{
					num3 += BroadcastAudioFrame(queuedPacket3);
				}
			}
			_bytesSentThisInterval += num3;
			EmitTelemetry();
		}

		private int BroadcastToAll(QueuedPacket pkt, PacketDelivery delivery)
		{
			int num = 0;
			foreach (var (num3, _) in _clients)
			{
				if (num3 != pkt.FromPeerId)
				{
					_transport.Send(num3, pkt.Payload, delivery);
					num += pkt.Payload.Length;
				}
			}
			return num;
		}

		private int BroadcastBoneUpdate(QueuedPacket pkt, long now, double msPerTick, float updateIntervalMs)
		{
			if (!_clients.TryGetValue(pkt.FromPeerId, out ConnectedClient value))
			{
				return 0;
			}
			int num = 0;
			foreach (var (num3, connectedClient2) in _clients)
			{
				if (num3 == pkt.FromPeerId)
				{
					continue;
				}
				float num4 = 1f;
				List<int>? distantClientPeerIds = value.DistantClientPeerIds;
				if (distantClientPeerIds != null && distantClientPeerIds.Contains(num3))
				{
					float num5 = Math.Abs(value.Position.Z - connectedClient2.Position.Z);
					if (num5 >= _settings.DistanceCutoff)
					{
						float num6 = Math.Clamp((num5 - _settings.DistanceCutoff) / (_settings.OuterDistanceCutoff - _settings.DistanceCutoff), 0f, 1f);
						float num7 = updateIntervalMs / 2000f;
						num4 = (float)Math.Exp((double)num6 * Math.Log(num7));
					}
				}
				float num8 = updateIntervalMs / num4;
				if (!value.LastTransmitTimes.TryGetValue(num3, out var value2))
				{
					value2 = 0L;
				}
				double num9 = (double)(now - value2) * msPerTick;
				if (num9 >= (double)num8)
				{
					_transport.Send(num3, pkt.Payload, PacketDelivery.Unreliable);
					value.LastTransmitTimes[num3] = now;
					num += pkt.Payload.Length;
				}
			}
			return num;
		}

		private int BroadcastAudioFrame(QueuedPacket pkt)
		{
			if (!_clients.TryGetValue(pkt.FromPeerId, out ConnectedClient value))
			{
				return 0;
			}
			int num = 0;
			foreach (var (num3, connectedClient2) in _clients)
			{
				if (num3 != pkt.FromPeerId && Vector3.Distance(value.Position, connectedClient2.Position) <= 60f)
				{
					_transport.Send(num3, pkt.Payload, PacketDelivery.Unreliable);
					num += pkt.Payload.Length;
				}
			}
			return num;
		}

		private void EmitTelemetry()
		{
			if (_settings.TelemetryEnabled)
			{
				long num = _telemetryWatch.ElapsedMilliseconds - _lastTelemetryTick;
				if (!((float)num < _settings.TelemetryIntervalMs))
				{
					float num2 = (float)_bytesSentThisInterval / 1024f / ((float)num / 1000f);
					float num3 = num2 / _settings.MaxBandwidthKbps * 100f;
					Console.WriteLine($"[BWM] {num2:F2} KB/s ({num3:F1}%) | Q: Hi={_highQueue.Count} Med={_mediumQueue.Count} Lo={_lowQueue.Count}");
					_bytesSentThisInterval = 0L;
					_lastTelemetryTick = _telemetryWatch.ElapsedMilliseconds;
				}
			}
		}
	}
}

Mods/Concentus.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Numerics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using Concentus.Celt;
using Concentus.Celt.Structs;
using Concentus.Common;
using Concentus.Common.CPlusPlus;
using Concentus.Enums;
using Concentus.Native;
using Concentus.Silk;
using Concentus.Silk.Enums;
using Concentus.Silk.Structs;
using Concentus.Structs;
using Microsoft.CodeAnalysis;
using Microsoft.Win32.SafeHandles;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("ParityTest, PublicKey=002400000480000094000000060200000024000052534131000400000100010071a2f675c04c87e64b9be6d37f5833c5285fb4ed883780cf6d61e80aee5d77950b2f06dd45bc634f53405f2a2b7b2332f4dfdcb0554ffc97b935e7343e76e733eea44346e56ac1098c12a66de71e324f2f503f9f2e32560910e2082d6943df50db42679a330e52979bd1eefbb59485d2c7420d158f6ab6d41bdf42d2172675e1")]
[assembly: InternalsVisibleTo("TestOpusEncode, PublicKey=002400000480000094000000060200000024000052534131000400000100010071a2f675c04c87e64b9be6d37f5833c5285fb4ed883780cf6d61e80aee5d77950b2f06dd45bc634f53405f2a2b7b2332f4dfdcb0554ffc97b935e7343e76e733eea44346e56ac1098c12a66de71e324f2f503f9f2e32560910e2082d6943df50db42679a330e52979bd1eefbb59485d2c7420d158f6ab6d41bdf42d2172675e1")]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("Logan Stromberg")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("© Xiph.Org Foundation, Skype Limited, CSIRO, Microsoft Corp.")]
[assembly: AssemblyDescription("This package is a portable C# implementation of the Opus audio compression codec (see https://opus-codec.org/ for more details). This package contains the Opus encoder, decoder, multistream codecs, repacketizer, as well as a port of the libspeexdsp resampler. It does NOT contain code to parse .ogg or .opus container files or to manage RTP packet streams. For better performance depending on your platform, see also the Concentus.Native package.")]
[assembly: AssemblyFileVersion("2.2.2.0")]
[assembly: AssemblyInformationalVersion("2.2.2+6c2328dc19044601e33a9c11628b8d60e1f3011c")]
[assembly: AssemblyProduct("Concentus")]
[assembly: AssemblyTitle("Concentus")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/lostromb/concentus")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.2.2.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
}
namespace Concentus
{
	public interface IOpusDecoder : IDisposable
	{
		OpusBandwidth Bandwidth { get; }

		uint FinalRange { get; }

		int Gain { get; set; }

		int LastPacketDuration { get; }

		int NumChannels { get; }

		int Pitch { get; }

		int SampleRate { get; }

		int Decode(ReadOnlySpan<byte> in_data, Span<float> out_pcm, int frame_size, bool decode_fec = false);

		int Decode(ReadOnlySpan<byte> in_data, Span<short> out_pcm, int frame_size, bool decode_fec = false);

		void ResetState();

		string GetVersionString();
	}
	public interface IOpusEncoder : IDisposable
	{
		OpusApplication Application { get; set; }

		int Bitrate { get; set; }

		int ForceChannels { get; set; }

		OpusBandwidth MaxBandwidth { get; set; }

		OpusBandwidth Bandwidth { get; set; }

		bool UseDTX { get; set; }

		int Complexity { get; set; }

		bool UseInbandFEC { get; set; }

		int PacketLossPercent { get; set; }

		bool UseVBR { get; set; }

		bool UseConstrainedVBR { get; set; }

		OpusSignal SignalType { get; set; }

		int Lookahead { get; }

		int SampleRate { get; }

		int NumChannels { get; }

		uint FinalRange { get; }

		int LSBDepth { get; set; }

		OpusFramesize ExpertFrameDuration { get; set; }

		OpusMode ForceMode { set; }

		bool PredictionDisabled { get; set; }

		int Encode(ReadOnlySpan<short> in_pcm, int frame_size, Span<byte> out_data, int max_data_bytes);

		int Encode(ReadOnlySpan<float> in_pcm, int frame_size, Span<byte> out_data, int max_data_bytes);

		void ResetState();

		string GetVersionString();
	}
	public interface IOpusMultiStreamDecoder : IDisposable
	{
		OpusBandwidth Bandwidth { get; }

		uint FinalRange { get; }

		int Gain { get; set; }

		int LastPacketDuration { get; }

		int SampleRate { get; }

		int NumChannels { get; }

		int DecodeMultistream(ReadOnlySpan<byte> data, Span<float> out_pcm, int frame_size, bool decode_fec);

		int DecodeMultistream(ReadOnlySpan<byte> data, Span<short> out_pcm, int frame_size, bool decode_fec);

		void ResetState();

		string GetVersionString();
	}
	public interface IOpusMultiStreamEncoder : IDisposable
	{
		OpusApplication Application { get; set; }

		OpusBandwidth Bandwidth { get; set; }

		int Bitrate { get; set; }

		int Complexity { get; set; }

		int NumChannels { get; }

		OpusFramesize ExpertFrameDuration { get; set; }

		uint FinalRange { get; }

		OpusMode ForceMode { set; }

		int Lookahead { get; }

		int LSBDepth { get; set; }

		OpusBandwidth MaxBandwidth { get; set; }

		int PacketLossPercent { get; set; }

		bool PredictionDisabled { get; set; }

		int SampleRate { get; }

		OpusSignal SignalType { get; set; }

		bool UseConstrainedVBR { get; set; }

		bool UseDTX { get; set; }

		bool UseInbandFEC { get; set; }

		bool UseVBR { get; set; }

		int EncodeMultistream(ReadOnlySpan<float> in_pcm, int frame_size, Span<byte> out_data, int max_data_bytes);

		int EncodeMultistream(ReadOnlySpan<short> in_pcm, int frame_size, Span<byte> out_data, int max_data_bytes);

		void ResetState();

		string GetVersionString();
	}
	public interface IResampler : IDisposable
	{
		int InputLatency { get; }

		int InputStride { get; set; }

		int OutputLatencySamples { get; }

		TimeSpan OutputLatency { get; }

		int OutputStride { get; set; }

		int Quality { get; set; }

		void GetRateFraction(out int ratio_num, out int ratio_den);

		void GetRates(out int in_rate, out int out_rate);

		void ResetMem();

		void SkipZeroes();

		void Process(int channel_index, Span<float> input, ref int in_len, Span<float> output, ref int out_len);

		void Process(int channel_index, Span<short> input, ref int in_len, Span<short> output, ref int out_len);

		void ProcessInterleaved(Span<float> input, ref int in_len, Span<float> output, ref int out_len);

		void ProcessInterleaved(Span<short> input, ref int in_len, Span<short> output, ref int out_len);

		void SetRateFraction(int ratio_num, int ratio_den, int in_rate, int out_rate);

		void SetRates(int in_rate, int out_rate);
	}
	public static class OpusCodecFactory
	{
		private static readonly object _mutex = new object();

		private static bool _nativeLibInitialized = false;

		private static bool _isNativeLibAvailable = false;

		private static bool _userAllowNativeLib = true;

		public static bool AttemptToUseNativeLibrary
		{
			get
			{
				return _userAllowNativeLib;
			}
			set
			{
				_userAllowNativeLib = value;
			}
		}

		public static IOpusEncoder CreateEncoder(int sampleRate, int numChannels, OpusApplication application = OpusApplication.OPUS_APPLICATION_AUDIO, TextWriter messageLogger = null)
		{
			if (_userAllowNativeLib && NativeLibraryAvailable(messageLogger))
			{
				return NativeOpusEncoder.Create(sampleRate, numChannels, application);
			}
			return new OpusEncoder(sampleRate, numChannels, application);
		}

		public static IOpusDecoder CreateDecoder(int sampleRate, int numChannels, TextWriter messageLogger = null)
		{
			if (_userAllowNativeLib && NativeLibraryAvailable(messageLogger))
			{
				return NativeOpusDecoder.Create(sampleRate, numChannels);
			}
			return new OpusDecoder(sampleRate, numChannels);
		}

		public static IOpusMultiStreamEncoder CreateMultiStreamEncoder(int sampleRate, int numChannels, int mappingFamily, out int streams, out int coupledStreams, byte[] mapping, OpusApplication application, TextWriter messageLogger = null)
		{
			if (_userAllowNativeLib && NativeLibraryAvailable(messageLogger))
			{
				return NativeOpusMultistreamEncoder.Create(sampleRate, numChannels, mappingFamily, out streams, out coupledStreams, mapping, application);
			}
			return OpusMSEncoder.CreateSurround(sampleRate, numChannels, mappingFamily, out streams, out coupledStreams, mapping, application);
		}

		public static IOpusMultiStreamDecoder CreateMultiStreamDecoder(int sampleRate, int numChannels, int streams, int coupledStreams, byte[] mapping, TextWriter messageLogger = null)
		{
			if (_userAllowNativeLib && NativeLibraryAvailable(messageLogger))
			{
				return NativeOpusMultistreamDecoder.Create(sampleRate, numChannels, streams, coupledStreams, mapping);
			}
			return new OpusMSDecoder(sampleRate, numChannels, streams, coupledStreams, mapping);
		}

		private static bool NativeLibraryAvailable(TextWriter messageLogger)
		{
			lock (_mutex)
			{
				if (!_nativeLibInitialized)
				{
					try
					{
						_isNativeLibAvailable = NativeOpus.Initialize(messageLogger);
						messageLogger?.WriteLine($"Is native opus available? {_isNativeLibAvailable}");
					}
					catch (Exception ex)
					{
						messageLogger?.WriteLine(ex.ToString());
					}
					_nativeLibInitialized = true;
				}
				return _isNativeLibAvailable;
			}
		}
	}
	internal static class Analysis
	{
		private const double M_PI = 3.141592653;

		private const float cA = 0.43157974f;

		private const float cB = 0.678484f;

		private const float cC = 0.08595542f;

		private const float cE = MathF.PI / 2f;

		private const int NB_TONAL_SKIP_BANDS = 9;

		internal static float fast_atan2f(float y, float x)
		{
			if (Inlines.ABS16(x) + Inlines.ABS16(y) < 1E-09f)
			{
				x *= 1E+12f;
				y *= 1E+12f;
			}
			float num = x * x;
			float num2 = y * y;
			if (num < num2)
			{
				float num3 = (num2 + 0.678484f * num) * (num2 + 0.08595542f * num);
				if (num3 != 0f)
				{
					return (0f - x) * y * (num2 + 0.43157974f * num) / num3 + ((y < 0f) ? (-MathF.PI / 2f) : (MathF.PI / 2f));
				}
				if (!(y < 0f))
				{
					return MathF.PI / 2f;
				}
				return -MathF.PI / 2f;
			}
			float num4 = (num + 0.678484f * num2) * (num + 0.08595542f * num2);
			if (num4 != 0f)
			{
				return x * y * (num + 0.43157974f * num2) / num4 + ((y < 0f) ? (-MathF.PI / 2f) : (MathF.PI / 2f)) - ((x * y < 0f) ? (-MathF.PI / 2f) : (MathF.PI / 2f));
			}
			return ((y < 0f) ? (-MathF.PI / 2f) : (MathF.PI / 2f)) - ((x * y < 0f) ? (-MathF.PI / 2f) : (MathF.PI / 2f));
		}

		internal static void tonality_analysis_init(TonalityAnalysisState tonal)
		{
			tonal.Reset();
		}

		internal static void tonality_get_info(TonalityAnalysisState tonal, AnalysisInfo info_out, int len)
		{
			int num = tonal.read_pos;
			int num2 = tonal.write_pos - tonal.read_pos;
			if (num2 < 0)
			{
				num2 += 200;
			}
			if (len > 480 && num != tonal.write_pos)
			{
				num++;
				if (num == 200)
				{
					num = 0;
				}
			}
			if (num == tonal.write_pos)
			{
				num--;
			}
			if (num < 0)
			{
				num = 199;
			}
			info_out.Assign(tonal.info[num]);
			tonal.read_subframe += len / 120;
			while (tonal.read_subframe >= 4)
			{
				tonal.read_subframe -= 4;
				tonal.read_pos++;
			}
			if (tonal.read_pos >= 200)
			{
				tonal.read_pos -= 200;
			}
			num2 = Inlines.IMAX(num2 - 10, 0);
			float num3 = 0f;
			int i;
			for (i = 0; i < 200 - num2; i++)
			{
				num3 += tonal.pmusic[i];
			}
			for (; i < 200; i++)
			{
				num3 += tonal.pspeech[i];
			}
			num3 = num3 * tonal.music_confidence + (1f - num3) * tonal.speech_confidence;
			info_out.music_prob = num3;
		}

		internal static void tonality_analysis<T>(TonalityAnalysisState tonal, CeltMode celt_mode, ReadOnlySpan<T> x, int len, int offset, int c1, int c2, int C, int lsb_depth, Downmix.downmix_func<T> downmix)
		{
			int num = 480;
			int num2 = 240;
			float[] angle = tonal.angle;
			float[] d_angle = tonal.d_angle;
			float[] d2_angle = tonal.d2_angle;
			float[] array = new float[18];
			float[] array2 = new float[18];
			float[] array3 = new float[8];
			float[] array4 = new float[25];
			float num3 = 97.40909f;
			float num4 = 0f;
			float[] array5 = new float[2];
			int num5 = 0;
			float num6 = 0f;
			tonal.last_transition++;
			float num7 = 1f / (float)Inlines.IMIN(20, 1 + tonal.count);
			float num8 = 1f / (float)Inlines.IMIN(50, 1 + tonal.count);
			float num9 = 1f / (float)Inlines.IMIN(1000, 1 + tonal.count);
			if (tonal.count < 4)
			{
				tonal.music_prob = 0.5f;
			}
			FFTState st = celt_mode.mdct.kfft[0];
			if (tonal.count == 0)
			{
				tonal.mem_fill = 240;
			}
			downmix(x, tonal.inmem, tonal.mem_fill, Inlines.IMIN(len, 720 - tonal.mem_fill), offset, c1, c2, C);
			if (tonal.mem_fill + len < 720)
			{
				tonal.mem_fill += len;
				return;
			}
			AnalysisInfo analysisInfo = tonal.info[tonal.write_pos++];
			if (tonal.write_pos >= 200)
			{
				tonal.write_pos -= 200;
			}
			int[] array6 = new int[960];
			int[] array7 = new int[960];
			float[] array8 = new float[240];
			float[] array9 = new float[240];
			for (int i = 0; i < num2; i++)
			{
				float num10 = Tables.analysis_window[i];
				array6[2 * i] = (int)(num10 * (float)tonal.inmem[i]);
				array6[2 * i + 1] = (int)(num10 * (float)tonal.inmem[num2 + i]);
				array6[2 * (num - i - 1)] = (int)(num10 * (float)tonal.inmem[num - i - 1]);
				array6[2 * (num - i - 1) + 1] = (int)(num10 * (float)tonal.inmem[num + num2 - i - 1]);
			}
			Arrays.MemMoveInt(tonal.inmem, 480, 0, 240);
			int num11 = len - (720 - tonal.mem_fill);
			downmix(x, tonal.inmem, 240, num11, offset + 720 - tonal.mem_fill, c1, c2, C);
			tonal.mem_fill = 240 + num11;
			KissFFT.opus_fft(st, array6, array7);
			for (int i = 1; i < num2; i++)
			{
				float x2 = (float)array7[2 * i] + (float)array7[2 * (num - i)];
				float y = (float)array7[2 * i + 1] - (float)array7[2 * (num - i) + 1];
				float x3 = (float)array7[2 * i + 1] + (float)array7[2 * (num - i) + 1];
				float y2 = (float)array7[2 * (num - i)] - (float)array7[2 * i];
				float num12 = 1f / (2f * MathF.PI) * fast_atan2f(y, x2);
				float num13 = num12 - angle[i];
				float num14 = num13 - d_angle[i];
				float num15 = 1f / (2f * MathF.PI) * fast_atan2f(y2, x3);
				float num16 = num15 - num12;
				float num17 = num16 - num13;
				float num18 = num14 - (float)Math.Floor(0.5f + num14);
				array9[i] = Inlines.ABS16(num18);
				num18 *= num18;
				num18 *= num18;
				float num19 = num17 - (float)Math.Floor(0.5f + num17);
				array9[i] += Inlines.ABS16(num19);
				num19 *= num19;
				num19 *= num19;
				float num20 = 0.25f * (d2_angle[i] + 2f * num18 + num19);
				array8[i] = 1f / (1f + 640f * num3 * num20) - 0.015f;
				angle[i] = num15;
				d_angle[i] = num16;
				d2_angle[i] = num19;
			}
			float num21 = 0f;
			float num22 = 0f;
			analysisInfo.activity = 0f;
			float num23 = 0f;
			float num24 = 0f;
			if (tonal.count == 0)
			{
				for (int j = 0; j < 18; j++)
				{
					tonal.lowE[j] = 1E+10f;
					tonal.highE[j] = -1E+10f;
				}
			}
			float num25 = 0f;
			float num26 = 0f;
			for (int j = 0; j < 18; j++)
			{
				float num27 = 0f;
				float num28 = 0f;
				float num29 = 0f;
				for (int i = Tables.tbands[j]; i < Tables.tbands[j + 1]; i++)
				{
					float num30 = (float)array7[2 * i] * (float)array7[2 * i] + (float)array7[2 * (num - i)] * (float)array7[2 * (num - i)] + (float)array7[2 * i + 1] * (float)array7[2 * i + 1] + (float)array7[2 * (num - i) + 1] * (float)array7[2 * (num - i) + 1];
					num30 *= 5.55E-17f;
					num27 += num30;
					num28 += num30 * array8[i];
					num29 += num30 * 2f * (0.5f - array9[i]);
				}
				tonal.E[tonal.E_count][j] = num27;
				num23 += num29 / (1E-15f + num27);
				num26 += (float)Math.Sqrt(num27 + 1E-10f);
				array2[j] = (float)Math.Log(num27 + 1E-10f);
				tonal.lowE[j] = Inlines.MIN32(array2[j], tonal.lowE[j] + 0.01f);
				tonal.highE[j] = Inlines.MAX32(array2[j], tonal.highE[j] - 0.1f);
				if (tonal.highE[j] < tonal.lowE[j] + 1f)
				{
					tonal.highE[j] += 0.5f;
					tonal.lowE[j] -= 0.5f;
				}
				num25 += (array2[j] - tonal.lowE[j]) / (1E-15f + tonal.highE[j] - tonal.lowE[j]);
				float num31;
				float num32 = (num31 = 0f);
				for (int i = 0; i < 8; i++)
				{
					num32 += (float)Math.Sqrt(tonal.E[i][j]);
					num31 += tonal.E[i][j];
				}
				float num33 = Inlines.MIN16(0.99f, num32 / (float)Math.Sqrt(1E-15 + (double)(8f * num31)));
				num33 *= num33;
				num33 *= num33;
				num24 += num33;
				array[j] = Inlines.MAX16(num28 / (1E-15f + num27), num33 * tonal.prev_band_tonality[j]);
				num21 += array[j];
				if (j >= 9)
				{
					num21 -= array[j - 18 + 9];
				}
				num22 = Inlines.MAX16(num22, (1f + 0.03f * (float)(j - 18)) * num21);
				num4 += array[j] * (float)(j - 8);
				tonal.prev_band_tonality[j] = array[j];
			}
			float num34 = 0f;
			num5 = 0;
			num6 = 0f;
			float num35 = 0.00057f / (float)(1 << Inlines.IMAX(0, lsb_depth - 8));
			num35 *= 134217730f;
			num35 *= num35;
			for (int j = 0; j < 21; j++)
			{
				float num36 = 0f;
				int num37 = Tables.extra_bands[j];
				int num38 = Tables.extra_bands[j + 1];
				for (int i = num37; i < num38; i++)
				{
					float num39 = (float)array7[2 * i] * (float)array7[2 * i] + (float)array7[2 * (num - i)] * (float)array7[2 * (num - i)] + (float)array7[2 * i + 1] * (float)array7[2 * i + 1] + (float)array7[2 * (num - i) + 1] * (float)array7[2 * (num - i) + 1];
					num36 += num39;
				}
				num6 = Inlines.MAX32(num6, num36);
				tonal.meanE[j] = Inlines.MAX32((1f - num9) * tonal.meanE[j], num36);
				num36 = Inlines.MAX32(num36, tonal.meanE[j]);
				num34 = Inlines.MAX32(0.05f * num34, num36);
				if ((double)num36 > 0.1 * (double)num34 && num36 * 1E+09f > num6 && num36 > num35 * (float)(num38 - num37))
				{
					num5 = j;
				}
			}
			if (tonal.count <= 2)
			{
				num5 = 20;
			}
			num26 = 20f * (float)Math.Log10(num26);
			tonal.Etracker = Inlines.MAX32(tonal.Etracker - 0.03f, num26);
			tonal.lowECount *= 1f - num8;
			if (num26 < tonal.Etracker - 30f)
			{
				tonal.lowECount += num8;
			}
			for (int i = 0; i < 8; i++)
			{
				float num40 = 0f;
				for (int j = 0; j < 16; j++)
				{
					num40 += Tables.dct_table[i * 16 + j] * array2[j];
				}
				array3[i] = num40;
			}
			num24 /= 18f;
			num25 /= 18f;
			if (tonal.count < 10)
			{
				num25 = 0.5f;
			}
			num23 /= 18f;
			analysisInfo.activity = num23 + (1f - num23) * num25;
			num21 = num22 / 9f;
			num21 = (tonal.prev_tonality = Inlines.MAX16(num21, tonal.prev_tonality * 0.8f));
			num4 /= 64f;
			analysisInfo.tonality_slope = num4;
			tonal.E_count = (tonal.E_count + 1) % 8;
			tonal.count++;
			analysisInfo.tonality = num21;
			for (int i = 0; i < 4; i++)
			{
				array4[i] = -0.12299f * (array3[i] + tonal.mem[i + 24]) + 0.49195f * (tonal.mem[i] + tonal.mem[i + 16]) + 0.69693f * tonal.mem[i + 8] - 1.4349f * tonal.cmean[i];
			}
			for (int i = 0; i < 4; i++)
			{
				tonal.cmean[i] = (1f - num7) * tonal.cmean[i] + num7 * array3[i];
			}
			for (int i = 0; i < 4; i++)
			{
				array4[4 + i] = 0.63246f * (array3[i] - tonal.mem[i + 24]) + 0.31623f * (tonal.mem[i] - tonal.mem[i + 16]);
			}
			for (int i = 0; i < 3; i++)
			{
				array4[8 + i] = 0.53452f * (array3[i] + tonal.mem[i + 24]) - 0.26726f * (tonal.mem[i] + tonal.mem[i + 16]) - 0.53452f * tonal.mem[i + 8];
			}
			if (tonal.count > 5)
			{
				for (int i = 0; i < 9; i++)
				{
					tonal.std[i] = (1f - num7) * tonal.std[i] + num7 * array4[i] * array4[i];
				}
			}
			for (int i = 0; i < 8; i++)
			{
				tonal.mem[i + 24] = tonal.mem[i + 16];
				tonal.mem[i + 16] = tonal.mem[i + 8];
				tonal.mem[i + 8] = tonal.mem[i];
				tonal.mem[i] = array3[i];
			}
			for (int i = 0; i < 9; i++)
			{
				array4[11 + i] = (float)Math.Sqrt(tonal.std[i]);
			}
			array4[20] = analysisInfo.tonality;
			array4[21] = analysisInfo.activity;
			array4[22] = num24;
			array4[23] = analysisInfo.tonality_slope;
			array4[24] = tonal.lowECount;
			MultiLayerPerceptron.mlp_process(Tables.net, array4, array5);
			array5[0] = 0.5f * (array5[0] + 1f);
			array5[0] = 0.01f + 1.21f * array5[0] * array5[0] - 0.23f * (float)Math.Pow(array5[0], 10.0);
			array5[1] = 0.5f * array5[1] + 0.5f;
			array5[0] = array5[1] * array5[0] + (1f - array5[1]) * 0.5f;
			float num41 = 5E-05f * array5[1];
			float num42 = 0.05f;
			float num43 = Inlines.MAX16(0.05f, Inlines.MIN16(0.95f, array5[0]));
			float num44 = Inlines.MAX16(0.05f, Inlines.MIN16(0.95f, tonal.music_prob));
			num42 = 0.01f + 0.05f * Inlines.ABS16(num43 - num44) / (num43 * (1f - num44) + num44 * (1f - num43));
			float num45 = (1f - tonal.music_prob) * (1f - num41) + tonal.music_prob * num41;
			float num46 = tonal.music_prob * (1f - num41) + (1f - tonal.music_prob) * num41;
			num45 *= (float)Math.Pow(1f - array5[0], num42);
			num46 *= (float)Math.Pow(array5[0], num42);
			tonal.music_prob = num46 / (num45 + num46);
			analysisInfo.music_prob = tonal.music_prob;
			float num47 = 1E-20f;
			float num48 = (float)Math.Pow(1f - array5[0], num42);
			float num49 = (float)Math.Pow(array5[0], num42);
			if (tonal.count == 1)
			{
				tonal.pspeech[0] = 0.5f;
				tonal.pmusic[0] = 0.5f;
			}
			float num50 = tonal.pspeech[0] + tonal.pspeech[1];
			float num51 = tonal.pmusic[0] + tonal.pmusic[1];
			tonal.pspeech[0] = num50 * (1f - num41) * num48;
			tonal.pmusic[0] = num51 * (1f - num41) * num49;
			for (int i = 1; i < 199; i++)
			{
				tonal.pspeech[i] = tonal.pspeech[i + 1] * num48;
				tonal.pmusic[i] = tonal.pmusic[i + 1] * num49;
			}
			tonal.pspeech[199] = num51 * num41 * num48;
			tonal.pmusic[199] = num50 * num41 * num49;
			for (int i = 0; i < 200; i++)
			{
				num47 += tonal.pspeech[i] + tonal.pmusic[i];
			}
			num47 = 1f / num47;
			for (int i = 0; i < 200; i++)
			{
				tonal.pspeech[i] *= num47;
				tonal.pmusic[i] *= num47;
			}
			num47 = tonal.pmusic[0];
			for (int i = 1; i < 200; i++)
			{
				num47 += tonal.pspeech[i];
			}
			if ((double)array5[1] > 0.75)
			{
				if ((double)tonal.music_prob > 0.9)
				{
					float num52 = 1f / (float)(++tonal.music_confidence_count);
					tonal.music_confidence_count = Inlines.IMIN(tonal.music_confidence_count, 500);
					tonal.music_confidence += num52 * Inlines.MAX16(-0.2f, array5[0] - tonal.music_confidence);
				}
				if ((double)tonal.music_prob < 0.1)
				{
					float num53 = 1f / (float)(++tonal.speech_confidence_count);
					tonal.speech_confidence_count = Inlines.IMIN(tonal.speech_confidence_count, 500);
					tonal.speech_confidence += num53 * Inlines.MIN16(0.2f, array5[0] - tonal.speech_confidence);
				}
			}
			else
			{
				if (tonal.music_confidence_count == 0)
				{
					tonal.music_confidence = 0.9f;
				}
				if (tonal.speech_confidence_count == 0)
				{
					tonal.speech_confidence = 0.1f;
				}
			}
			if (tonal.last_music != ((tonal.music_prob > 0.5f) ? 1 : 0))
			{
				tonal.last_transition = 0;
			}
			tonal.last_music = ((tonal.music_prob > 0.5f) ? 1 : 0);
			analysisInfo.bandwidth = num5;
			analysisInfo.noisiness = num23;
			analysisInfo.valid = 1;
		}

		internal static void run_analysis<T>(TonalityAnalysisState analysis, CeltMode celt_mode, ReadOnlySpan<T> analysis_pcm, int analysis_frame_size, int frame_size, int c1, int c2, int C, int Fs, int lsb_depth, Downmix.downmix_func<T> downmix, AnalysisInfo analysis_info)
		{
			if (!analysis_pcm.IsEmpty)
			{
				analysis_frame_size = Inlines.IMIN(195 * Fs / 100, analysis_frame_size);
				int num = analysis_frame_size - analysis.analysis_offset;
				int num2 = analysis.analysis_offset;
				do
				{
					tonality_analysis(analysis, celt_mode, analysis_pcm, Inlines.IMIN(480, num), num2, c1, c2, C, lsb_depth, downmix);
					num2 += 480;
					num -= 480;
				}
				while (num > 0);
				analysis.analysis_offset = analysis_frame_size;
				analysis.analysis_offset -= frame_size;
			}
			analysis_info.valid = 0;
			tonality_get_info(analysis, analysis_info, frame_size);
		}
	}
	internal static class CodecHelpers
	{
		private const int MAX_DYNAMIC_FRAMESIZE = 24;

		internal static byte gen_toc(OpusMode mode, int framerate, OpusBandwidth bandwidth, int channels)
		{
			int num = 0;
			while (framerate < 400)
			{
				framerate <<= 1;
				num++;
			}
			byte b;
			switch (mode)
			{
			case OpusMode.MODE_SILK_ONLY:
				b = (byte)((int)(bandwidth - 1101) << 5);
				b |= (byte)(num - 2 << 3);
				break;
			case OpusMode.MODE_CELT_ONLY:
			{
				int num2 = (int)(bandwidth - 1102);
				if (num2 < 0)
				{
					num2 = 0;
				}
				b = 128;
				b |= (byte)(num2 << 5);
				b |= (byte)(num << 3);
				break;
			}
			default:
				b = 96;
				b |= (byte)((int)(bandwidth - 1104) << 4);
				b |= (byte)(num - 2 << 3);
				break;
			}
			return (byte)(b | (byte)(((channels == 2) ? 1u : 0u) << 2));
		}

		internal static void hp_cutoff(ReadOnlySpan<short> input, int input_ptr, int cutoff_Hz, Span<short> output, int output_ptr, int[] hp_mem, int len, int channels, int Fs)
		{
			int[] array = new int[3];
			int[] array2 = new int[2];
			int num = Inlines.silk_DIV32_16(Inlines.silk_SMULBB(2471, cutoff_Hz), Fs / 1000);
			int num2 = (array[0] = 268435456 - Inlines.silk_MUL(471, num));
			array[1] = Inlines.silk_LSHIFT(-num2, 1);
			array[2] = num2;
			int num3 = Inlines.silk_RSHIFT(num2, 6);
			array2[0] = Inlines.silk_SMULWW(num3, Inlines.silk_SMULWW(num, num) - 8388608);
			array2[1] = Inlines.silk_SMULWW(num3, num3);
			Filters.silk_biquad_alt(input, input_ptr, array, array2, hp_mem, 0, output, output_ptr, len, channels);
			if (channels == 2)
			{
				Filters.silk_biquad_alt(input, input_ptr + 1, array, array2, hp_mem, 2, output, output_ptr + 1, len, channels);
			}
		}

		internal static void dc_reject(ReadOnlySpan<short> input, int input_ptr, int cutoff_Hz, Span<short> output, int output_ptr, int[] hp_mem, int len, int channels, int Fs)
		{
			int shift = Inlines.celt_ilog2(Fs / (cutoff_Hz * 3));
			for (int i = 0; i < channels; i++)
			{
				for (int j = 0; j < len; j++)
				{
					int num = Inlines.SHL32(Inlines.EXTEND32(input[channels * j + i + input_ptr]), 15);
					int num2 = num - hp_mem[2 * i];
					hp_mem[2 * i] += Inlines.PSHR32(num - hp_mem[2 * i], shift);
					int a = num2 - hp_mem[2 * i + 1];
					hp_mem[2 * i + 1] += Inlines.PSHR32(num2 - hp_mem[2 * i + 1], shift);
					output[channels * j + i + output_ptr] = Inlines.EXTRACT16(Inlines.SATURATE(Inlines.PSHR32(a, 15), 32767));
				}
			}
		}

		internal static void stereo_fade(short[] pcm_buf, int g1, int g2, int overlap48, int frame_size, int channels, int[] window, int Fs)
		{
			int num = 48000 / Fs;
			int num2 = overlap48 / num;
			g1 = 32767 - g1;
			g2 = 32767 - g2;
			int i;
			for (i = 0; i < num2; i++)
			{
				int num3 = Inlines.MULT16_16_Q15(window[i * num], window[i * num]);
				int a = Inlines.SHR32(Inlines.MAC16_16(Inlines.MULT16_16(num3, g2), 32767 - num3, g1), 15);
				int b = Inlines.EXTRACT16(Inlines.HALF32(pcm_buf[i * channels] - pcm_buf[i * channels + 1]));
				b = Inlines.MULT16_16_Q15(a, b);
				pcm_buf[i * channels] = (short)(pcm_buf[i * channels] - b);
				pcm_buf[i * channels + 1] = (short)(pcm_buf[i * channels + 1] + b);
			}
			for (; i < frame_size; i++)
			{
				int b2 = Inlines.EXTRACT16(Inlines.HALF32(pcm_buf[i * channels] - pcm_buf[i * channels + 1]));
				b2 = Inlines.MULT16_16_Q15(g2, b2);
				pcm_buf[i * channels] = (short)(pcm_buf[i * channels] - b2);
				pcm_buf[i * channels + 1] = (short)(pcm_buf[i * channels + 1] + b2);
			}
		}

		internal static void gain_fade(short[] buffer, int buf_ptr, int g1, int g2, int overlap48, int frame_size, int channels, int[] window, int Fs)
		{
			int num = 48000 / Fs;
			int num2 = overlap48 / num;
			if (channels == 1)
			{
				for (int i = 0; i < num2; i++)
				{
					int num3 = Inlines.MULT16_16_Q15(window[i * num], window[i * num]);
					int a = Inlines.SHR32(Inlines.MAC16_16(Inlines.MULT16_16(num3, g2), 32767 - num3, g1), 15);
					buffer[buf_ptr + i] = (short)Inlines.MULT16_16_Q15(a, buffer[buf_ptr + i]);
				}
			}
			else
			{
				for (int i = 0; i < num2; i++)
				{
					int num4 = Inlines.MULT16_16_Q15(window[i * num], window[i * num]);
					int a2 = Inlines.SHR32(Inlines.MAC16_16(Inlines.MULT16_16(num4, g2), 32767 - num4, g1), 15);
					buffer[buf_ptr + i * 2] = (short)Inlines.MULT16_16_Q15(a2, buffer[buf_ptr + i * 2]);
					buffer[buf_ptr + i * 2 + 1] = (short)Inlines.MULT16_16_Q15(a2, buffer[buf_ptr + i * 2 + 1]);
				}
			}
			int num5 = 0;
			do
			{
				for (int i = num2; i < frame_size; i++)
				{
					buffer[buf_ptr + i * channels + num5] = (short)Inlines.MULT16_16_Q15(g2, buffer[buf_ptr + i * channels + num5]);
				}
			}
			while (++num5 < channels);
		}

		internal static float transient_boost(Span<float> E, int E_ptr, float[] E_1, int LM, int maxM)
		{
			float num = 0f;
			float num2 = 0f;
			int num3 = Inlines.IMIN(maxM, (1 << LM) + 1);
			for (int i = E_ptr; i < num3 + E_ptr; i++)
			{
				num += E[i];
				num2 += E_1[i];
			}
			float num4 = num * num2 / (float)(num3 * num3);
			return Inlines.MIN16(1f, (float)Math.Sqrt(Inlines.MAX16(0f, 0.05f * (num4 - 2f))));
		}

		internal static int transient_viterbi(float[] E, float[] E_1, int N, int frame_cost, int rate)
		{
			float[][] array = Arrays.InitTwoDimensionalArray<float>(24, 16);
			int[][] array2 = Arrays.InitTwoDimensionalArray<int>(24, 16);
			float num = ((rate < 80) ? 0f : ((rate <= 160) ? (((float)rate - 80f) / 80f) : 1f));
			for (int i = 0; i < 16; i++)
			{
				array2[0][i] = -1;
				array[0][i] = 1E+10f;
			}
			for (int i = 0; i < 4; i++)
			{
				array[0][1 << i] = (float)(frame_cost + rate * (1 << i)) * (1f + num * transient_boost(E, 0, E_1, i, N + 1));
				array2[0][1 << i] = i;
			}
			for (int i = 1; i < N; i++)
			{
				for (int j = 2; j < 16; j++)
				{
					array[i][j] = array[i - 1][j - 1];
					array2[i][j] = j - 1;
				}
				for (int j = 0; j < 4; j++)
				{
					array2[i][1 << j] = 1;
					float num2 = array[i - 1][1];
					for (int k = 1; k < 4; k++)
					{
						float num3 = array[i - 1][(1 << k + 1) - 1];
						if (num3 < num2)
						{
							array2[i][1 << j] = (1 << k + 1) - 1;
							num2 = num3;
						}
					}
					float num4 = (float)(frame_cost + rate * (1 << j)) * (1f + num * transient_boost(E, i, E_1, j, N - i + 1));
					array[i][1 << j] = num2;
					if (N - i < 1 << j)
					{
						array[i][1 << j] += num4 * (float)(N - i) / (float)(1 << j);
					}
					else
					{
						array[i][1 << j] += num4;
					}
				}
			}
			int num5 = 1;
			float num6 = array[N - 1][1];
			for (int i = 2; i < 16; i++)
			{
				if (array[N - 1][i] < num6)
				{
					num6 = array[N - 1][i];
					num5 = i;
				}
			}
			for (int i = N - 1; i >= 0; i--)
			{
				num5 = array2[i][num5];
			}
			return num5;
		}

		internal static int optimize_framesize<T>(ReadOnlySpan<T> x, int len, int C, int Fs, int bitrate, int tonality, float[] mem, int buffering, Downmix.downmix_func<T> downmix)
		{
			float[] array = new float[28];
			float[] array2 = new float[27];
			int num = 0;
			int num2 = Fs / 400;
			int[] array3 = new int[num2];
			array[0] = mem[0];
			array2[0] = 1f / (1f + mem[0]);
			int num3;
			int num4;
			if (buffering != 0)
			{
				num3 = 2 * num2 - buffering;
				len -= num3;
				array[1] = mem[1];
				array2[1] = 1f / (1f + mem[1]);
				array[2] = mem[2];
				array2[2] = 1f / (1f + mem[2]);
				num4 = 3;
			}
			else
			{
				num4 = 1;
				num3 = 0;
			}
			int num5 = Inlines.IMIN(len / num2, 24);
			int num6 = 0;
			int i;
			for (i = 0; i < num5; i++)
			{
				float num7 = 1f;
				downmix(x, array3, 0, num2, i * num2 + num3, 0, -2, C);
				if (i == 0)
				{
					num6 = array3[0];
				}
				for (int j = 0; j < num2; j++)
				{
					int num8 = array3[j];
					num7 += (float)(num8 - num6) * (float)(num8 - num6);
					num6 = num8;
				}
				array[i + num4] = num7;
				array2[i + num4] = 1f / num7;
			}
			array[i + num4] = array[i + num4 - 1];
			if (buffering != 0)
			{
				num5 = Inlines.IMIN(24, num5 + 2);
			}
			num = transient_viterbi(array, array2, num5, (int)((1f + 0.5f * (float)tonality) * (float)(60 * C + 40)), bitrate / 400);
			mem[0] = array[1 << num];
			if (buffering != 0)
			{
				mem[1] = array[(1 << num) + 1];
				mem[2] = array[(1 << num) + 2];
			}
			return num;
		}

		internal static int frame_size_select(int frame_size, OpusFramesize variable_duration, int Fs)
		{
			if (frame_size < Fs / 400)
			{
				return -1;
			}
			int num;
			switch (variable_duration)
			{
			case OpusFramesize.OPUS_FRAMESIZE_ARG:
				num = frame_size;
				break;
			case OpusFramesize.OPUS_FRAMESIZE_VARIABLE:
				num = Fs / 50;
				break;
			case OpusFramesize.OPUS_FRAMESIZE_2_5_MS:
			case OpusFramesize.OPUS_FRAMESIZE_5_MS:
			case OpusFramesize.OPUS_FRAMESIZE_10_MS:
			case OpusFramesize.OPUS_FRAMESIZE_20_MS:
			case OpusFramesize.OPUS_FRAMESIZE_40_MS:
			case OpusFramesize.OPUS_FRAMESIZE_60_MS:
				num = Inlines.IMIN(3 * Fs / 50, Fs / 400 << (int)(variable_duration - 5001));
				break;
			default:
				return -1;
			}
			if (num > frame_size)
			{
				return -1;
			}
			if (400 * num != Fs && 200 * num != Fs && 100 * num != Fs && 50 * num != Fs && 25 * num != Fs && 50 * num != 3 * Fs)
			{
				return -1;
			}
			return num;
		}

		internal static int compute_frame_size<T>(ReadOnlySpan<T> analysis_pcm, int frame_size, OpusFramesize variable_duration, int C, int Fs, int bitrate_bps, int delay_compensation, Downmix.downmix_func<T> downmix, float[] subframe_mem, bool analysis_enabled)
		{
			if (analysis_enabled && variable_duration == OpusFramesize.OPUS_FRAMESIZE_VARIABLE && frame_size >= Fs / 200)
			{
				int num = 3;
				num = optimize_framesize(analysis_pcm, frame_size, C, Fs, bitrate_bps, 0, subframe_mem, delay_compensation, downmix);
				while (Fs / 400 << num > frame_size)
				{
					num--;
				}
				frame_size = Fs / 400 << num;
			}
			else
			{
				frame_size = frame_size_select(frame_size, variable_duration, Fs);
			}
			if (frame_size < 0)
			{
				return -1;
			}
			return frame_size;
		}

		internal static int compute_stereo_width(ReadOnlySpan<short> pcm, int pcm_ptr, int frame_size, int Fs, StereoWidthState mem)
		{
			int num = Fs / frame_size;
			int a = 32767 - 819175 / Inlines.IMAX(50, num);
			int num3;
			int num2;
			int num4 = (num3 = (num2 = 0));
			for (int i = 0; i < frame_size - 3; i += 4)
			{
				int num5 = 0;
				int num6 = 0;
				int num7 = 0;
				int num8 = pcm_ptr + 2 * i;
				int num9 = pcm[num8];
				int num10 = pcm[num8 + 1];
				num5 = Inlines.SHR32(Inlines.MULT16_16(num9, num9), 2);
				num6 = Inlines.SHR32(Inlines.MULT16_16(num9, num10), 2);
				num7 = Inlines.SHR32(Inlines.MULT16_16(num10, num10), 2);
				num9 = pcm[num8 + 2];
				num10 = pcm[num8 + 3];
				num5 += Inlines.SHR32(Inlines.MULT16_16(num9, num9), 2);
				num6 += Inlines.SHR32(Inlines.MULT16_16(num9, num10), 2);
				num7 += Inlines.SHR32(Inlines.MULT16_16(num10, num10), 2);
				num9 = pcm[num8 + 4];
				num10 = pcm[num8 + 5];
				num5 += Inlines.SHR32(Inlines.MULT16_16(num9, num9), 2);
				num6 += Inlines.SHR32(Inlines.MULT16_16(num9, num10), 2);
				num7 += Inlines.SHR32(Inlines.MULT16_16(num10, num10), 2);
				num9 = pcm[num8 + 6];
				num10 = pcm[num8 + 7];
				num5 += Inlines.SHR32(Inlines.MULT16_16(num9, num9), 2);
				num6 += Inlines.SHR32(Inlines.MULT16_16(num9, num10), 2);
				num7 += Inlines.SHR32(Inlines.MULT16_16(num10, num10), 2);
				num4 += Inlines.SHR32(num5, 10);
				num3 += Inlines.SHR32(num6, 10);
				num2 += Inlines.SHR32(num7, 10);
			}
			mem.XX += Inlines.MULT16_32_Q15(a, num4 - mem.XX);
			mem.XY += Inlines.MULT16_32_Q15(a, num3 - mem.XY);
			mem.YY += Inlines.MULT16_32_Q15(a, num2 - mem.YY);
			mem.XX = Inlines.MAX32(0, mem.XX);
			mem.XY = Inlines.MAX32(0, mem.XY);
			mem.YY = Inlines.MAX32(0, mem.YY);
			if (Inlines.MAX32(mem.XX, mem.YY) > 210)
			{
				int num11 = Inlines.celt_sqrt(mem.XX);
				int num12 = Inlines.celt_sqrt(mem.YY);
				int num13 = Inlines.celt_sqrt(num11);
				int num14 = Inlines.celt_sqrt(num12);
				mem.XY = Inlines.MIN32(mem.XY, num11 * num12);
				int num15 = Inlines.SHR32(Inlines.frac_div32(mem.XY, 1 + Inlines.MULT16_16(num11, num12)), 16);
				int b = 32767 * Inlines.ABS16(num13 - num14) / (1 + num13 + num14);
				int num16 = Inlines.MULT16_16_Q15(Inlines.celt_sqrt(1073741824 - Inlines.MULT16_16(num15, num15)), b);
				mem.smoothed_width += (num16 - mem.smoothed_width) / num;
				mem.max_follower = Inlines.MAX16(mem.max_follower - 655 / num, mem.smoothed_width);
			}
			else
			{
				int num16 = 0;
				int num15 = 32767;
				int b = 0;
			}
			return Inlines.EXTRACT16(Inlines.MIN32(32767, 20 * mem.max_follower));
		}

		internal static void smooth_fade(Span<short> in1, int in1_ptr, Span<short> in2, int in2_ptr, Span<short> output, int output_ptr, int overlap, int channels, int[] window, int Fs)
		{
			int num = 48000 / Fs;
			for (int i = 0; i < channels; i++)
			{
				for (int j = 0; j < overlap; j++)
				{
					int num2 = Inlines.MULT16_16_Q15(window[j * num], window[j * num]);
					output[output_ptr + j * channels + i] = (short)Inlines.SHR32(Inlines.MAC16_16(Inlines.MULT16_16(num2, in2[in2_ptr + j * channels + i]), 32767 - num2, in1[in1_ptr + j * channels + i]), 15);
				}
			}
		}

		internal static string opus_strerror(int error)
		{
			string[] array = new string[8] { "success", "invalid argument", "buffer too small", "internal error", "corrupted stream", "request not implemented", "invalid state", "memory allocation failed" };
			if (error > 0 || error < -7)
			{
				return "unknown error";
			}
			return array[-error];
		}

		internal static string GetVersionString()
		{
			return "Concentus 2.1.2";
		}
	}
	internal static class Downmix
	{
		internal delegate void downmix_func<T>(ReadOnlySpan<T> _x, Span<int> sub, int sub_ptr, int subframe, int offset, int c1, int c2, int C);

		internal static void downmix_float(ReadOnlySpan<float> x, Span<int> sub, int sub_ptr, int subframe, int offset, int c1, int c2, int C)
		{
			for (int i = 0; i < subframe; i++)
			{
				sub[sub_ptr + i] = Inlines.FLOAT2INT16(x[(i + offset) * C + c1]);
			}
			if (c2 > -1)
			{
				for (int i = 0; i < subframe; i++)
				{
					sub[sub_ptr + i] += Inlines.FLOAT2INT16(x[(i + offset) * C + c2]);
				}
			}
			else if (c2 == -2)
			{
				for (int j = 1; j < C; j++)
				{
					int num = j;
					for (int i = 0; i < subframe; i++)
					{
						sub[sub_ptr + i] += Inlines.FLOAT2INT16(x[(i + offset) * C + num]);
					}
				}
			}
			int num2 = 4096;
			num2 = ((C != -2) ? (num2 / 2) : (num2 / C));
			for (int i = 0; i < subframe; i++)
			{
				sub[sub_ptr + i] *= num2;
			}
		}

		internal static void downmix_int(ReadOnlySpan<short> x, Span<int> sub, int sub_ptr, int subframe, int offset, int c1, int c2, int C)
		{
			for (int i = 0; i < subframe; i++)
			{
				sub[i + sub_ptr] = x[(i + offset) * C + c1];
			}
			if (c2 > -1)
			{
				for (int i = 0; i < subframe; i++)
				{
					sub[i + sub_ptr] += x[(i + offset) * C + c2];
				}
			}
			else if (c2 == -2)
			{
				for (int j = 1; j < C; j++)
				{
					for (int i = 0; i < subframe; i++)
					{
						sub[i + sub_ptr] += x[(i + offset) * C + j];
					}
				}
			}
			int num = 4096;
			num = ((C != -2) ? (num / 2) : (num / C));
			for (int i = 0; i < subframe; i++)
			{
				sub[i + sub_ptr] *= num;
			}
		}
	}
	internal static class MultiLayerPerceptron
	{
		private const int MAX_NEURONS = 100;

		internal static float tansig_approx(float x)
		{
			float num = 1f;
			if (!(x < 8f))
			{
				return 1f;
			}
			if (!(x > -8f))
			{
				return -1f;
			}
			if (x < 0f)
			{
				x = 0f - x;
				num = -1f;
			}
			int num2 = (int)Math.Floor(0.5f + 25f * x);
			x -= 0.04f * (float)num2;
			float num3 = Tables.tansig_table[num2];
			float num4 = 1f - num3 * num3;
			num3 += x * num4 * (1f - num3 * x);
			return num * num3;
		}

		internal static void mlp_process(MLP m, float[] input, float[] output)
		{
			float[] array = new float[100];
			float[] weights = m.weights;
			int num = 0;
			for (int i = 0; i < m.topo[1]; i++)
			{
				float num2 = weights[num];
				num++;
				for (int j = 0; j < m.topo[0]; j++)
				{
					num2 += input[j] * weights[num];
					num++;
				}
				array[i] = tansig_approx(num2);
			}
			for (int i = 0; i < m.topo[2]; i++)
			{
				float num3 = weights[num];
				num++;
				for (int k = 0; k < m.topo[1]; k++)
				{
					num3 += array[k] * weights[num];
					num++;
				}
				output[i] = tansig_approx(num3);
			}
		}
	}
	internal static class OpusCompare
	{
		private const int NBANDS = 21;

		private const int NFREQS = 240;

		private const int TEST_WIN_SIZE = 480;

		private const int TEST_WIN_STEP = 120;

		private static readonly int[] BANDS = new int[22]
		{
			0, 2, 4, 6, 8, 10, 12, 14, 16, 20,
			24, 28, 32, 40, 48, 56, 68, 80, 96, 120,
			156, 200
		};

		private static void band_energy(Pointer<float> _out, Pointer<float> _ps, Pointer<int> _bands, int _nbands, Pointer<float> _in, int _nchannels, int _nframes, int _window_sz, int _step, int _downsample)
		{
			Pointer<float> pointer = Concentus.Common.CPlusPlus.Pointer.Malloc<float>((3 + _nchannels) * _window_sz);
			Pointer<float> pointer2 = pointer.Point(_window_sz);
			Pointer<float> pointer3 = pointer2.Point(_window_sz);
			Pointer<float> pointer4 = pointer3.Point(_window_sz);
			int num = _window_sz / 2;
			for (int i = 0; i < _window_sz; i++)
			{
				pointer[i] = (float)(0.5 - 0.5 * Math.Cos(Math.PI * 2.0 / (double)(_window_sz - 1) * (double)i));
			}
			for (int i = 0; i < _window_sz; i++)
			{
				pointer2[i] = (float)Math.Cos(Math.PI * 2.0 / (double)_window_sz * (double)i);
			}
			for (int i = 0; i < _window_sz; i++)
			{
				pointer3[i] = (float)Math.Sin(Math.PI * 2.0 / (double)_window_sz * (double)i);
			}
			for (int j = 0; j < _nframes; j++)
			{
				for (int k = 0; k < _nchannels; k++)
				{
					for (int l = 0; l < _window_sz; l++)
					{
						pointer4[k * _window_sz + l] = pointer[l] * _in[(j * _step + l) * _nchannels + k];
					}
				}
				int i;
				for (int m = (i = 0); m < _nbands; m++)
				{
					float[] array = new float[2];
					for (; i < _bands[m + 1]; i++)
					{
						for (int k = 0; k < _nchannels; k++)
						{
							int num2 = 0;
							float num3;
							float num4 = (num3 = 0f);
							for (int l = 0; l < _window_sz; l++)
							{
								num4 += pointer2[num2] * pointer4[k * _window_sz + l];
								num3 -= pointer3[num2] * pointer4[k * _window_sz + l];
								num2 += i;
								if (num2 >= _window_sz)
								{
									num2 -= _window_sz;
								}
							}
							num4 *= (float)_downsample;
							num3 *= (float)_downsample;
							_ps[(j * num + i) * _nchannels + k] = num4 * num4 + num3 * num3 + 100000f;
							array[k] += _ps[(j * num + i) * _nchannels + k];
						}
					}
					if (_out != null)
					{
						_out[(j * _nbands + m) * _nchannels] = array[0] / (float)(_bands[m + 1] - _bands[m]);
						if (_nchannels == 2)
						{
							_out[(j * _nbands + m) * _nchannels + 1] = array[1] / (float)(_bands[m + 1] - _bands[m]);
						}
					}
				}
			}
		}

		internal static float compare(float[] x, float[] y, int nchannels, int rate = 48000)
		{
			int num = x.Length;
			int num2 = y.Length;
			int num3 = 21;
			int num4 = 240;
			if (rate != 8000 && rate != 12000 && rate != 16000 && rate != 24000 && rate != 48000)
			{
				throw new ArgumentException("Sampling rate must be 8000, 12000, 16000, 24000, or 48000\n");
			}
			int num5;
			if (rate != 48000)
			{
				num5 = 48000 / rate;
				switch (rate)
				{
				case 8000:
					num3 = 13;
					break;
				case 12000:
					num3 = 15;
					break;
				case 16000:
					num3 = 17;
					break;
				case 24000:
					num3 = 19;
					break;
				}
				num4 = 240 / num5;
			}
			else
			{
				num5 = 1;
			}
			if (num != num2 * num5)
			{
				throw new ArgumentException("Sample counts do not match");
			}
			if (num < 480)
			{
				throw new ArgumentException("Insufficient sample data");
			}
			int num6 = (num - 480 + 120) / 120;
			Pointer<float> pointer = Concentus.Common.CPlusPlus.Pointer.Malloc<float>(num6 * 21 * nchannels);
			Pointer<float> pointer2 = Concentus.Common.CPlusPlus.Pointer.Malloc<float>(num6 * 240 * nchannels);
			Pointer<float> pointer3 = Concentus.Common.CPlusPlus.Pointer.Malloc<float>(num6 * num4 * nchannels);
			band_energy(pointer, pointer2, BANDS.GetPointer(), 21, x.GetPointer(), nchannels, num6, 480, 120, 1);
			band_energy(null, pointer3, BANDS.GetPointer(), num3, y.GetPointer(), nchannels, num6, 480 / num5, 120 / num5, num5);
			for (int i = 0; i < num6; i++)
			{
				int j;
				for (j = 1; j < 21; j++)
				{
					for (int k = 0; k < nchannels; k++)
					{
						pointer[(i * 21 + j) * nchannels + k] += 0.1f * pointer[(i * 21 + j - 1) * nchannels + k];
					}
				}
				j = 20;
				while (j-- > 0)
				{
					for (int k = 0; k < nchannels; k++)
					{
						pointer[(i * 21 + j) * nchannels + k] += 0.03f * pointer[(i * 21 + j + 1) * nchannels + k];
					}
				}
				if (i > 0)
				{
					for (j = 0; j < 21; j++)
					{
						for (int k = 0; k < nchannels; k++)
						{
							pointer[(i * 21 + j) * nchannels + k] += 0.5f * pointer[((i - 1) * 21 + j) * nchannels + k];
						}
					}
				}
				if (nchannels == 2)
				{
					for (j = 0; j < 21; j++)
					{
						float num7 = pointer[(i * 21 + j) * nchannels];
						float num8 = pointer[(i * 21 + j) * nchannels + 1];
						pointer[(i * 21 + j) * nchannels] += 0.01f * num8;
						pointer[(i * 21 + j) * nchannels + 1] += 0.01f * num7;
					}
				}
				for (j = 0; j < num3; j++)
				{
					for (int l = BANDS[j]; l < BANDS[j + 1]; l++)
					{
						for (int k = 0; k < nchannels; k++)
						{
							pointer2[(i * 240 + l) * nchannels + k] += 0.1f * pointer[(i * 21 + j) * nchannels + k];
							pointer3[(i * num4 + l) * nchannels + k] += 0.1f * pointer[(i * 21 + j) * nchannels + k];
						}
					}
				}
			}
			for (int j = 0; j < num3; j++)
			{
				for (int l = BANDS[j]; l < BANDS[j + 1]; l++)
				{
					for (int k = 0; k < nchannels; k++)
					{
						float num9 = pointer2[l * nchannels + k];
						float num10 = pointer3[l * nchannels + k];
						for (int i = 1; i < num6; i++)
						{
							float num11 = pointer2[(i * 240 + l) * nchannels + k];
							float num12 = pointer3[(i * num4 + l) * nchannels + k];
							pointer2[(i * 240 + l) * nchannels + k] += num9;
							pointer3[(i * num4 + l) * nchannels + k] += num10;
							num9 = num11;
							num10 = num12;
						}
					}
				}
			}
			int num13 = rate switch
			{
				48000 => BANDS[21], 
				12000 => BANDS[num3], 
				_ => BANDS[num3] - 3, 
			};
			double num14 = 0.0;
			for (int i = 0; i < num6; i++)
			{
				double num15 = 0.0;
				for (int j = 0; j < num3; j++)
				{
					double num16 = 0.0;
					for (int l = BANDS[j]; l < BANDS[j + 1] && l < num13; l++)
					{
						for (int k = 0; k < nchannels; k++)
						{
							float num17 = pointer3[(i * num4 + l) * nchannels + k] / pointer2[(i * 240 + l) * nchannels + k];
							float num18 = num17 - (float)Math.Log(num17) - 1f;
							if (l >= 79 && l <= 81)
							{
								num18 *= 0.1f;
							}
							if (l == 80)
							{
								num18 *= 0.1f;
							}
							num16 += (double)num18;
						}
					}
					num16 /= (double)((BANDS[j + 1] - BANDS[j]) * nchannels);
					num15 += num16 * num16;
				}
				num15 /= 21.0;
				num15 *= num15;
				num14 += num15 * num15;
			}
			num14 = Math.Pow(num14 / (double)num6, 0.0625);
			float result = (float)(100.0 * (1.0 - 0.5 * Math.Log(1.0 + num14) / Math.Log(1.13)));
			_ = 0f;
			return result;
		}
	}
	internal static class OpusConstants
	{
		internal const int OPUS_AUTO = -1000;

		internal const int OPUS_BITRATE_MAX = -1;

		internal const int NB_FRAMES = 8;

		internal const int NB_TBANDS = 18;

		internal const int NB_TOT_BANDS = 21;

		internal const int NB_TONAL_SKIP_BANDS = 9;

		internal const int ANALYSIS_BUF_SIZE = 720;

		internal const int DETECT_SIZE = 200;

		internal const int MAX_ENCODER_BUFFER = 480;
	}
	public class OpusException : Exception
	{
		public int OpusErrorCode { get; private set; }

		internal OpusException()
			: base("Unknown error")
		{
			OpusErrorCode = -100;
		}

		internal OpusException(string message)
			: base(message)
		{
			OpusErrorCode = -100;
		}

		internal OpusException(int opusError)
			: base(CodecHelpers.opus_strerror(opusError))
		{
			OpusErrorCode = opusError;
		}

		internal OpusException(string message, int opusError)
			: base(message)
		{
			OpusErrorCode = opusError;
		}
	}
	internal static class OpusMultistream
	{
		internal static int validate_layout(ChannelLayout layout)
		{
			int num = layout.nb_streams + layout.nb_coupled_streams;
			if (num > 255)
			{
				return 0;
			}
			for (int i = 0; i < layout.nb_channels; i++)
			{
				if (layout.mapping[i] >= num && layout.mapping[i] != byte.MaxValue)
				{
					return 0;
				}
			}
			return 1;
		}

		internal static int get_left_channel(ChannelLayout layout, int stream_id, int prev)
		{
			for (int i = ((prev >= 0) ? (prev + 1) : 0); i < layout.nb_channels; i++)
			{
				if (layout.mapping[i] == stream_id * 2)
				{
					return i;
				}
			}
			return -1;
		}

		internal static int get_right_channel(ChannelLayout layout, int stream_id, int prev)
		{
			for (int i = ((prev >= 0) ? (prev + 1) : 0); i < layout.nb_channels; i++)
			{
				if (layout.mapping[i] == stream_id * 2 + 1)
				{
					return i;
				}
			}
			return -1;
		}

		internal static int get_mono_channel(ChannelLayout layout, int stream_id, int prev)
		{
			for (int i = ((prev >= 0) ? (prev + 1) : 0); i < layout.nb_channels; i++)
			{
				if (layout.mapping[i] == stream_id + layout.nb_coupled_streams)
				{
					return i;
				}
			}
			return -1;
		}
	}
	internal static class Tables
	{
		internal static readonly float[] dct_table = new float[128]
		{
			0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f,
			0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.351851f, 0.33833f, 0.311806f, 0.2733f,
			0.224292f, 0.166664f, 0.102631f, 0.034654f, -0.034654f, -0.102631f, -0.166664f, -0.224292f, -0.2733f, -0.311806f,
			-0.33833f, -0.351851f, 0.34676f, 0.293969f, 0.196424f, 0.068975f, -0.068975f, -0.196424f, -0.293969f, -0.34676f,
			-0.34676f, -0.293969f, -0.196424f, -0.068975f, 0.068975f, 0.196424f, 0.293969f, 0.34676f, 0.33833f, 0.224292f,
			0.034654f, -0.166664f, -0.311806f, -0.351851f, -0.2733f, -0.102631f, 0.102631f, 0.2733f, 0.351851f, 0.311806f,
			0.166664f, -0.034654f, -0.224292f, -0.33833f, 0.326641f, 0.135299f, -0.135299f, -0.326641f, -0.326641f, -0.135299f,
			0.135299f, 0.326641f, 0.326641f, 0.135299f, -0.135299f, -0.326641f, -0.326641f, -0.135299f, 0.135299f, 0.326641f,
			0.311806f, 0.034654f, -0.2733f, -0.33833f, -0.102631f, 0.224292f, 0.351851f, 0.166664f, -0.166664f, -0.351851f,
			-0.224292f, 0.102631f, 0.33833f, 0.2733f, -0.034654f, -0.311806f, 0.293969f, -0.068975f, -0.34676f, -0.196424f,
			0.196424f, 0.34676f, 0.068975f, -0.293969f, -0.293969f, 0.068975f, 0.34676f, 0.196424f, -0.196424f, -0.34676f,
			-0.068975f, 0.293969f, 0.2733f, -0.166664f, -0.33833f, 0.034654f, 0.351851f, 0.102631f, -0.311806f, -0.224292f,
			0.224292f, 0.311806f, -0.102631f, -0.351851f, -0.034654f, 0.33833f, 0.166664f, -0.2733f
		};

		internal static readonly float[] analysis_window = new float[240]
		{
			4.3E-05f, 0.000171f, 0.000385f, 0.000685f, 0.001071f, 0.001541f, 0.002098f, 0.002739f, 0.003466f, 0.004278f,
			0.005174f, 0.006156f, 0.007222f, 0.008373f, 0.009607f, 0.010926f, 0.012329f, 0.013815f, 0.015385f, 0.017037f,
			0.018772f, 0.02059f, 0.02249f, 0.024472f, 0.026535f, 0.028679f, 0.030904f, 0.03321f, 0.035595f, 0.03806f,
			0.040604f, 0.043227f, 0.045928f, 0.048707f, 0.051564f, 0.054497f, 0.057506f, 0.060591f, 0.063752f, 0.066987f,
			0.070297f, 0.07368f, 0.077136f, 0.080665f, 0.084265f, 0.087937f, 0.091679f, 0.095492f, 0.099373f, 0.103323f,
			0.107342f, 0.111427f, 0.115579f, 0.119797f, 0.12408f, 0.128428f, 0.132839f, 0.137313f, 0.141849f, 0.146447f,
			0.151105f, 0.155823f, 0.1606f, 0.165435f, 0.170327f, 0.175276f, 0.18028f, 0.18534f, 0.190453f, 0.195619f,
			0.200838f, 0.206107f, 0.211427f, 0.216797f, 0.222215f, 0.22768f, 0.233193f, 0.238751f, 0.244353f, 0.25f,
			0.255689f, 0.261421f, 0.267193f, 0.273005f, 0.278856f, 0.284744f, 0.29067f, 0.296632f, 0.302628f, 0.308658f,
			0.314721f, 0.320816f, 0.326941f, 0.333097f, 0.33928f, 0.345492f, 0.351729f, 0.357992f, 0.36428f, 0.37059f,
			0.376923f, 0.383277f, 0.389651f, 0.396044f, 0.402455f, 0.408882f, 0.415325f, 0.421783f, 0.428254f, 0.434737f,
			0.441231f, 0.447736f, 0.454249f, 0.46077f, 0.467298f, 0.473832f, 0.48037f, 0.486912f, 0.493455f, 0.5f,
			0.506545f, 0.513088f, 0.51963f, 0.526168f, 0.532702f, 0.53923f, 0.545751f, 0.552264f, 0.558769f, 0.565263f,
			0.571746f, 0.578217f, 0.584675f, 0.591118f, 0.597545f, 0.603956f, 0.610349f, 0.616723f, 0.623077f, 0.62941f,
			0.63572f, 0.642008f, 0.648271f, 0.654508f, 0.66072f, 0.666903f, 0.673059f, 0.679184f, 0.685279f, 0.691342f,
			0.697372f, 0.703368f, 0.70933f, 0.715256f, 0.721144f, 0.726995f, 0.732807f, 0.738579f, 0.744311f, 0.75f,
			0.755647f, 0.761249f, 0.766807f, 0.77232f, 0.777785f, 0.783203f, 0.788573f, 0.793893f, 0.799162f, 0.804381f,
			0.809547f, 0.81466f, 0.81972f, 0.824724f, 0.829673f, 0.834565f, 0.8394f, 0.844177f, 0.848895f, 0.853553f,
			0.858151f, 0.862687f, 0.867161f, 0.871572f, 0.87592f, 0.880203f, 0.884421f, 0.888573f, 0.892658f, 0.896677f,
			0.900627f, 0.904508f, 0.908321f, 0.912063f, 0.915735f, 0.919335f, 0.922864f, 0.92632f, 0.929703f, 0.933013f,
			0.936248f, 0.939409f, 0.942494f, 0.945503f, 0.948436f, 0.951293f, 0.954072f, 0.956773f, 0.959396f, 0.96194f,
			0.964405f, 0.96679f, 0.969096f, 0.971321f, 0.973465f, 0.975528f, 0.97751f, 0.97941f, 0.981228f, 0.982963f,
			0.984615f, 0.986185f, 0.987671f, 0.989074f, 0.990393f, 0.991627f, 0.992778f, 0.993844f, 0.994826f, 0.995722f,
			0.996534f, 0.997261f, 0.997902f, 0.998459f, 0.998929f, 0.999315f, 0.999615f, 0.999829f, 0.999957f, 1f
		};

		internal static readonly int[] tbands = new int[19]
		{
			2, 4, 6, 8, 10, 12, 14, 16, 20, 24,
			28, 32, 40, 48, 56, 68, 80, 96, 120
		};

		internal static readonly int[] extra_bands = new int[22]
		{
			1, 2, 4, 6, 8, 10, 12, 14, 16, 20,
			24, 28, 32, 40, 48, 56, 68, 80, 96, 120,
			160, 200
		};

		internal static readonly float[] weights = new float[422]
		{
			-0.0941125f,
			-0.302976f,
			-0.603555f,
			-0.19393f,
			-0.185983f,
			-0.601617f,
			-0.0465317f,
			-0.114563f,
			-0.103599f,
			-0.618938f,
			-0.317859f,
			-0.169949f,
			-0.0702885f,
			0.148065f,
			0.409524f,
			0.548432f,
			0.367649f,
			-0.494393f,
			0.764306f,
			-1.83957f,
			0.170849f,
			12.786f,
			-1.08848f,
			-1.27284f,
			-16.2606f,
			24.1773f,
			-5.57454f,
			-0.17276f,
			-0.163388f,
			-0.224421f,
			-0.0948944f,
			-0.0728695f,
			-0.26557f,
			-0.100283f,
			-0.0515459f,
			-0.146142f,
			-0.120674f,
			-0.180655f,
			0.12857f,
			0.442138f,
			-0.493735f,
			0.167767f,
			0.206699f,
			-0.197567f,
			0.417999f,
			1.50364f,
			-0.773341f,
			-10.0401f,
			0.401872f,
			2.97966f,
			15.2165f,
			-1.88905f,
			-1.19254f,
			0.0285397f,
			-0.00405139f,
			0.0707565f,
			0.00825699f,
			-0.0927269f,
			-0.010393f,
			-0.00428882f,
			-0.00489743f,
			-0.0709731f,
			-0.00255992f,
			0.0395619f,
			0.226424f,
			0.0325231f,
			0.162175f,
			-0.100118f,
			0.485789f,
			0.12697f,
			0.285937f,
			0.0155637f,
			0.10546f,
			3.05558f,
			1.15059f,
			-1.00904f,
			-1.83088f,
			3.31766f,
			-3.42516f,
			-0.119135f,
			-0.0405654f,
			0.00690068f,
			0.0179877f,
			-0.0382487f,
			0.00597941f,
			-0.0183611f,
			0.00190395f,
			-0.144322f,
			-0.0435671f,
			0.000990594f,
			0.221087f,
			0.142405f,
			0.484066f,
			0.404395f,
			0.511955f,
			-0.237255f,
			0.241742f,
			0.35045f,
			-0.699428f,
			10.3993f,
			2.6507f,
			-2.43459f,
			-4.18838f,
			1.05928f,
			1.71067f,
			0.00667811f,
			-0.0721335f,
			-0.0397346f,
			0.0362704f,
			-0.11496f,
			-0.0235776f,
			0.0082161f,
			-0.0141741f,
			-0.0329699f,
			-0.0354253f,
			0.00277404f,
			-0.290654f,
			-1.14767f,
			-0.319157f,
			-0.686544f,
			0.36897f,
			0.478899f,
			0.182579f,
			-0.411069f,
			0.881104f,
			-4.60683f,
			1.4697f,
			325f / (356f * MathF.E),
			-1.81905f,
			-30.1699f,
			5.55225f,
			0.0019508f,
			-0.123576f,
			-0.0727332f,
			-0.0641597f,
			-0.0534458f,
			-0.108166f,
			-0.0937368f,
			-0.0697883f,
			-0.0275475f,
			-0.192309f,
			-0.110074f,
			0.285375f,
			-0.405597f,
			0.0926724f,
			-0.287881f,
			-0.851193f,
			-0.099493f,
			-0.233764f,
			-1.2852f,
			1.13611f,
			3.12168f,
			-0.0699f,
			-1.86216f,
			2.65292f,
			-7.31036f,
			2.44776f,
			-0.00111802f,
			-0.0632786f,
			-0.0376296f,
			-0.149851f,
			0.142963f,
			0.184368f,
			0.123433f,
			0.0756158f,
			0.117312f,
			0.0933395f,
			0.0692163f,
			0.0842592f,
			0.0704683f,
			0.0589963f,
			0.0942205f,
			-0.448862f,
			0.0262677f,
			0.270352f,
			-0.262317f,
			0.172586f,
			2.00227f,
			-0.159216f,
			0.038422f,
			10.2073f,
			4.15536f,
			-2.3407f,
			-0.0550265f,
			0.00964792f,
			-0.141336f,
			0.0274501f,
			0.0343921f,
			-0.0487428f,
			0.0950172f,
			-0.00775017f,
			-0.0372492f,
			-0.00548121f,
			-0.0663695f,
			0.0960506f,
			-0.200008f,
			-0.0412827f,
			0.58728f,
			0.0515787f,
			0.337254f,
			0.855024f,
			0.668371f,
			-0.114904f,
			-3.62962f,
			-0.467477f,
			-0.215472f,
			2.61537f,
			0.406117f,
			-1.36373f,
			0.0425394f,
			0.12208f,
			0.0934502f,
			0.123055f,
			0.0340935f,
			-0.142466f,
			0.035037f,
			-0.0490666f,
			0.0733208f,
			0.0576672f,
			0.123984f,
			-0.0517194f,
			-0.253018f,
			0.590565f,
			0.145849f,
			0.315185f,
			0.221534f,
			-0.149081f,
			0.216161f,
			-0.349575f,
			24.5664f,
			-0.994196f,
			0.614289f,
			-18.7905f,
			-2.83277f,
			-0.716801f,
			-0.347201f,
			0.479515f,
			-0.246027f,
			0.0758683f,
			0.137293f,
			-0.17781f,
			0.118751f,
			-0.00108329f,
			-0.237334f,
			0.355732f,
			-0.12991f,
			-0.0547627f,
			-0.318576f,
			-0.325524f,
			0.180494f,
			-0.0625604f,
			0.141219f,
			0.344064f,
			0.37658f,
			-0.591772f,
			5.8427f,
			-0.38075f,
			0.221894f,
			-1.41934f,
			-1879430f,
			1.34114f,
			0.0283355f,
			-0.0447856f,
			-0.0211466f,
			-0.0256927f,
			0.0139618f,
			0.0207934f,
			-0.0107666f,
			0.0110969f,
			0.0586069f,
			-0.0253545f,
			-0.0328433f,
			0.11872f,
			-0.216943f,
			0.145748f,
			0.119808f,
			-0.0915211f,
			-0.120647f,
			-0.0787719f,
			-0.143644f,
			-0.595116f,
			-1.152f,
			-1.25335f,
			-1.17092f,
			4.34023f,
			-975268f,
			-1.37033f,
			-0.0401123f,
			0.210602f,
			-0.136656f,
			0.135962f,
			-0.0523293f,
			0.0444604f,
			0.0143928f,
			0.00412666f,
			-0.0193003f,
			0.218452f,
			-0.110204f,
			-2.02563f,
			0.918238f,
			-2.45362f,
			1.19542f,
			-0.061362f,
			-1.92243f,
			0.308111f,
			0.49764f,
			0.912356f,
			0.209272f,
			-2.34525f,
			2.19326f,
			-6.47121f,
			1.69771f,
			-0.725123f,
			0.0118929f,
			0.0377944f,
			0.0554003f,
			0.0226452f,
			-0.0704421f,
			-0.0300309f,
			0.0122978f,
			-0.0041782f,
			-0.0686612f,
			0.0313115f,
			0.039111f,
			0.364111f,
			-0.0945548f,
			0.0229876f,
			-0.17414f,
			0.329795f,
			0.114714f,
			0.30022f,
			0.106997f,
			0.132355f,
			5.79932f,
			0.908058f,
			-0.905324f,
			-3.3561f,
			0.190647f,
			0.184211f,
			-0.673648f,
			0.231807f,
			-0.0586222f,
			0.230752f,
			-0.438277f,
			0.245857f,
			-0.17215f,
			0.0876383f,
			-0.720512f,
			0.162515f,
			0.0170571f,
			0.101781f,
			0.388477f,
			1.32931f,
			1.08548f,
			-0.936301f,
			-2.36958f,
			-6.71988f,
			-3.44376f,
			2.13818f,
			14.2318f,
			4.91459f,
			-3.09052f,
			-9.69191f,
			-0.768234f,
			1.79604f,
			0.0549653f,
			0.163399f,
			0.0797025f,
			0.0343933f,
			-0.0555876f,
			-0.00505673f,
			0.0187258f,
			0.0326628f,
			0.0231486f,
			0.15573f,
			0.0476223f,
			-0.254824f,
			1.60155f,
			-0.801221f,
			2.55496f,
			0.737629f,
			-1.36249f,
			-0.695463f,
			-2.44301f,
			-1.73188f,
			3.95279f,
			1.89068f,
			0.486087f,
			-11.3343f,
			3941600f,
			-0.381439f,
			0.12115f,
			-0.906927f,
			2.93878f,
			1.6388f,
			0.882811f,
			0.874344f,
			1.21726f,
			-0.874545f,
			0.321706f,
			0.785055f,
			0.946558f,
			-0.575066f,
			-3.46553f,
			0.884905f,
			0.0924047f,
			-9.90712f,
			0.391338f,
			0.160103f,
			-2.04954f,
			4.1455f,
			0.0684029f,
			-0.144761f,
			-0.285282f,
			0.379244f,
			-1.1584f,
			-0.0277241f,
			-9.85f,
			-4.82386f,
			3.71333f,
			3.87308f,
			3.52558f
		};

		internal static readonly int[] topo = new int[3] { 25, 15, 2 };

		internal static readonly MLP net = new MLP
		{
			layers = 3,
			topo = topo,
			weights = weights
		};

		internal static readonly float[] tansig_table = new float[201]
		{
			0f, 0.039979f, 0.07983f, 0.119427f, 0.158649f, 0.197375f, 0.235496f, 0.272905f, 0.309507f, 0.345214f,
			0.379949f, 0.413644f, 0.446244f, 0.4777f, 0.507977f, 0.53705f, 0.5649f, 0.591519f, 0.616909f, 0.641077f,
			0.664037f, 0.685809f, 0.706419f, 0.725897f, 0.744277f, 0.761594f, 0.777888f, 0.793199f, 0.807569f, 0.82104f,
			0.833655f, 0.845456f, 0.856485f, 0.866784f, 0.876393f, 0.885352f, 0.893698f, 0.901468f, 0.908698f, 0.91542f,
			0.921669f, 0.927473f, 0.932862f, 0.937863f, 0.942503f, 0.946806f, 0.950795f, 0.954492f, 0.957917f, 0.96109f,
			0.964028f, 0.966747f, 0.969265f, 0.971594f, 0.973749f, 0.975743f, 0.977587f, 0.979293f, 0.980869f, 0.982327f,
			0.983675f, 0.984921f, 0.986072f, 0.987136f, 0.988119f, 0.989027f, 0.989867f, 0.990642f, 0.991359f, 0.99202f,
			0.992631f, 0.993196f, 0.993718f, 0.994199f, 0.994644f, 0.995055f, 0.995434f, 0.995784f, 0.996108f, 0.996407f,
			0.996682f, 0.996937f, 0.997172f, 0.997389f, 0.99759f, 0.997775f, 0.997946f, 0.998104f, 0.998249f, 0.998384f,
			0.998508f, 0.998623f, 0.998728f, 0.998826f, 0.998916f, 0.999f, 0.999076f, 0.999147f, 0.999213f, 0.999273f,
			0.999329f, 0.999381f, 0.999428f, 0.999472f, 0.999513f, 0.99955f, 0.999585f, 0.999617f, 0.999646f, 0.999673f,
			0.999699f, 0.999722f, 0.999743f, 0.999763f, 0.999781f, 0.999798f, 0.999813f, 0.999828f, 0.999841f, 0.999853f,
			0.999865f, 0.999875f, 0.999885f, 0.999893f, 0.999902f, 0.999909f, 0.999916f, 0.999923f, 0.999929f, 0.999934f,
			0.999939f, 0.999944f, 0.999948f, 0.999952f, 0.999956f, 0.999959f, 0.999962f, 0.999965f, 0.999968f, 0.99997f,
			0.999973f, 0.999975f, 0.999977f, 0.999978f, 0.99998f, 0.999982f, 0.999983f, 0.999984f, 0.999986f, 0.999987f,
			0.999988f, 0.999989f, 0.99999f, 0.99999f, 0.999991f, 0.999992f, 0.999992f, 0.999993f, 0.999994f, 0.999994f,
			0.999994f, 0.999995f, 0.999995f, 0.999996f, 0.999996f, 0.999996f, 0.999997f, 0.999997f, 0.999997f, 0.999997f,
			0.999997f, 0.999998f, 0.999998f, 0.999998f, 0.999998f, 0.999998f, 0.999998f, 0.999999f, 0.999999f, 0.999999f,
			0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f,
			1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f,
			1f
		};

		internal static readonly int[] mono_voice_bandwidth_thresholds = new int[8] { 11000, 1000, 14000, 1000, 17000, 1000, 21000, 2000 };

		internal static readonly int[] mono_music_bandwidth_thresholds = new int[8] { 12000, 1000, 15000, 1000, 18000, 2000, 22000, 2000 };

		internal static readonly int[] stereo_voice_bandwidth_thresholds = new int[8] { 11000, 1000, 14000, 1000, 21000, 2000, 28000, 2000 };

		internal static readonly int[] stereo_music_bandwidth_thresholds = new int[8] { 12000, 1000, 18000, 2000, 21000, 2000, 30000, 2000 };

		internal const int stereo_voice_threshold = 30000;

		internal const int stereo_music_threshold = 30000;

		internal static readonly int[][] mode_thresholds = new int[2][]
		{
			new int[2] { 64000, 16000 },
			new int[2] { 36000, 16000 }
		};
	}
	public static class ResamplerFactory
	{
		public static IResampler CreateResampler(int numChannels, int inRate, int outRate, int quality, TextWriter logger = null)
		{
			return CreateResampler(numChannels, inRate, outRate, inRate, outRate, quality, logger);
		}

		public static IResampler CreateResampler(int numChannels, int ratioNum, int ratioDen, int inRate, int outRate, int quality, TextWriter logger = null)
		{
			if (numChannels <= 0)
			{
				throw new ArgumentOutOfRangeException("numChannels");
			}
			if (ratioNum <= 0)
			{
				throw new ArgumentOutOfRangeException("ratioNum");
			}
			if (ratioDen <= 0)
			{
				throw new ArgumentOutOfRangeException("ratioDen");
			}
			if (inRate <= 0)
			{
				throw new ArgumentOutOfRangeException("inRate");
			}
			if (outRate <= 0)
			{
				throw new ArgumentOutOfRangeException("outRate");
			}
			if (quality < 0 || quality > 10)
			{
				throw new ArgumentOutOfRangeException("quality", "Quality must be between 0 and 10");
			}
			return new SpeexResampler(numChannels, ratioNum, ratioDen, inRate, outRate, quality);
		}
	}
}
namespace Concentus.Silk
{
	internal static class ApplySineWindow
	{
		private static readonly short[] freq_table_Q16 = new short[27]
		{
			12111, 9804, 8235, 7100, 6239, 5565, 5022, 4575, 4202, 3885,
			3612, 3375, 3167, 2984, 2820, 2674, 2542, 2422, 2313, 2214,
			2123, 2038, 1961, 1889, 1822, 1760, 1702
		};

		internal static void silk_apply_sine_window(short[] px_win, int px_win_ptr, short[] px, int px_ptr, int win_type, int length)
		{
			int num = (length >> 2) - 4;
			int num2 = freq_table_Q16[num];
			int num3 = Inlines.silk_SMULWB(num2, -num2);
			int num4;
			int num5;
			if (win_type == 1)
			{
				num4 = 0;
				num5 = num2 + Inlines.silk_RSHIFT(length, 3);
			}
			else
			{
				num4 = 65536;
				num5 = 65536 + Inlines.silk_RSHIFT(num3, 1) + Inlines.silk_RSHIFT(length, 4);
			}
			for (num = 0; num < length; num += 4)
			{
				int num6 = px_win_ptr + num;
				int num7 = px_ptr + num;
				px_win[num6] = (short)Inlines.silk_SMULWB(Inlines.silk_RSHIFT(num4 + num5, 1), px[num7]);
				px_win[num6 + 1] = (short)Inlines.silk_SMULWB(num5, px[num7 + 1]);
				num4 = Inlines.silk_SMULWB(num5, num3) + Inlines.silk_LSHIFT(num5, 1) - num4 + 1;
				num4 = Inlines.silk_min(num4, 65536);
				px_win[num6 + 2] = (short)Inlines.silk_SMULWB(Inlines.silk_RSHIFT(num4 + num5, 1), px[num7 + 2]);
				px_win[num6 + 3] = (short)Inlines.silk_SMULWB(num4, px[num7 + 3]);
				num5 = Inlines.silk_SMULWB(num4, num3) + Inlines.silk_LSHIFT(num4, 1) - num5;
				num5 = Inlines.silk_min(num5, 65536);
			}
		}
	}
	internal static class BurgModified
	{
		private const int MAX_FRAME_SIZE = 384;

		private const int QA = 25;

		private const int N_BITS_HEAD_ROOM = 2;

		private const int MIN_RSHIFTS = -16;

		private const int MAX_RSHIFTS = 7;

		internal static void silk_burg_modified(BoxedValueInt res_nrg, BoxedValueInt res_nrg_Q, int[] A_Q16, short[] x, int x_ptr, int minInvGain_Q30, int subfr_length, int nb_subfr, int D)
		{
			int[] array = new int[16];
			int[] array2 = new int[16];
			int[] array3 = new int[16];
			int[] array4 = new int[17];
			int[] array5 = new int[17];
			int[] array6 = new int[16];
			long num = Inlines.silk_inner_prod16_aligned_64(x, x_ptr, x, x_ptr, subfr_length * nb_subfr);
			int num2 = Inlines.silk_CLZ64(num);
			int num3 = 35 - num2;
			if (num3 > 7)
			{
				num3 = 7;
			}
			if (num3 < -16)
			{
				num3 = -16;
			}
			int num4 = (int)((num3 <= 0) ? Inlines.silk_LSHIFT32((int)num, -num3) : Inlines.silk_RSHIFT64(num, num3));
			array5[0] = (array4[0] = num4 + Inlines.silk_SMMUL(42950, num4) + 1);
			Arrays.MemSetInt(array, 0, 16);
			if (num3 > 0)
			{
				for (int i = 0; i < nb_subfr; i++)
				{
					int num5 = x_ptr + i * subfr_length;
					for (int j = 1; j < D + 1; j++)
					{
						array[j - 1] += (int)Inlines.silk_RSHIFT64(Inlines.silk_inner_prod16_aligned_64(x, num5, x, num5 + j, subfr_length - j), num3);
					}
				}
			}
			else
			{
				for (int i = 0; i < nb_subfr; i++)
				{
					int num5 = x_ptr + i * subfr_length;
					CeltPitchXCorr.pitch_xcorr(x, num5, x, num5 + 1, array6, subfr_length - D, D);
					for (int j = 1; j < D + 1; j++)
					{
						int k = j + subfr_length - D;
						int num6 = 0;
						for (; k < subfr_length; k++)
						{
							num6 = Inlines.MAC16_16(num6, x[num5 + k], x[num5 + k - j]);
						}
						array6[j - 1] += num6;
					}
					for (int j = 1; j < D + 1; j++)
					{
						array[j - 1] += Inlines.silk_LSHIFT32(array6[j - 1], -num3);
					}
				}
			}
			Arrays.MemCopy(array, 0, array2, 0, 16);
			array5[0] = (array4[0] = num4 + Inlines.silk_SMMUL(42950, num4) + 1);
			int num7 = 1073741824;
			int num8 = 0;
			for (int j = 0; j < D; j++)
			{
				int num9;
				int num10;
				if (num3 > -2)
				{
					for (int i = 0; i < nb_subfr; i++)
					{
						int num5 = x_ptr + i * subfr_length;
						int b = -Inlines.silk_LSHIFT32(x[num5 + j], 16 - num3);
						int b2 = -Inlines.silk_LSHIFT32(x[num5 + subfr_length - j - 1], 16 - num3);
						num9 = Inlines.silk_LSHIFT32(x[num5 + j], 9);
						num10 = Inlines.silk_LSHIFT32(x[num5 + subfr_length - j - 1], 9);
						for (int l = 0; l < j; l++)
						{
							array[l] = Inlines.silk_SMLAWB(array[l], b, x[num5 + j - l - 1]);
							array2[l] = Inlines.silk_SMLAWB(array2[l], b2, x[num5 + subfr_length - j + l]);
							int b3 = array3[l];
							num9 = Inlines.silk_SMLAWB(num9, b3, x[num5 + j - l - 1]);
							num10 = Inlines.silk_SMLAWB(num10, b3, x[num5 + subfr_length - j + l]);
						}
						num9 = Inlines.silk_LSHIFT32(-num9, 7 - num3);
						num10 = Inlines.silk_LSHIFT32(-num10, 7 - num3);
						for (int l = 0; l <= j; l++)
						{
							array4[l] = Inlines.silk_SMLAWB(array4[l], num9, x[num5 + j - l]);
							array5[l] = Inlines.silk_SMLAWB(array5[l], num10, x[num5 + subfr_length - j + l - 1]);
						}
					}
				}
				else
				{
					for (int i = 0; i < nb_subfr; i++)
					{
						int num5 = x_ptr + i * subfr_length;
						int b = -Inlines.silk_LSHIFT32(x[num5 + j], -num3);
						int b2 = -Inlines.silk_LSHIFT32(x[num5 + subfr_length - j - 1], -num3);
						num9 = Inlines.silk_LSHIFT32(x[num5 + j], 17);
						num10 = Inlines.silk_LSHIFT32(x[num5 + subfr_length - j - 1], 17);
						for (int l = 0; l < j; l++)
						{
							array[l] = Inlines.silk_MLA(array[l], b, x[num5 + j - l - 1]);
							array2[l] = Inlines.silk_MLA(array2[l], b2, x[num5 + subfr_length - j + l]);
							int c = Inlines.silk_RSHIFT_ROUND(array3[l], 8);
							num9 = Inlines.silk_MLA(num9, x[num5 + j - l - 1], c);
							num10 = Inlines.silk_MLA(num10, x[num5 + subfr_length - j + l], c);
						}
						num9 = -num9;
						num10 = -num10;
						for (int l = 0; l <= j; l++)
						{
							array4[l] = Inlines.silk_SMLAWW(array4[l], num9, Inlines.silk_LSHIFT32(x[num5 + j - l], -num3 - 1));
							array5[l] = Inlines.silk_SMLAWW(array5[l], num10, Inlines.silk_LSHIFT32(x[num5 + subfr_length - j + l - 1], -num3 - 1));
						}
					}
				}
				num9 = array[j];
				num10 = array2[j];
				int a = 0;
				int num11 = Inlines.silk_ADD32(array5[0], array4[0]);
				for (int l = 0; l < j; l++)
				{
					int b3 = array3[l];
					num2 = Inlines.silk_CLZ32(Inlines.silk_abs(b3)) - 1;
					num2 = Inlines.silk_min(7, num2);
					int c = Inlines.silk_LSHIFT32(b3, num2);
					num9 = Inlines.silk_ADD_LSHIFT32(num9, Inlines.silk_SMMUL(array2[j - l - 1], c), 7 - num2);
					num10 = Inlines.silk_ADD_LSHIFT32(num10, Inlines.silk_SMMUL(array[j - l - 1], c), 7 - num2);
					a = Inlines.silk_ADD_LSHIFT32(a, Inlines.silk_SMMUL(array5[j - l], c), 7 - num2);
					num11 = Inlines.silk_ADD_LSHIFT32(num11, Inlines.silk_SMMUL(Inlines.silk_ADD32(array5[l + 1], array4[l + 1]), c), 7 - num2);
				}
				array4[j + 1] = num9;
				array5[j + 1] = num10;
				a = Inlines.silk_ADD32(a, num10);
				a = Inlines.silk_LSHIFT32(-a, 1);
				int num12 = ((Inlines.silk_abs(a) >= num11) ? ((a > 0) ? int.MaxValue : int.MinValue) : Inlines.silk_DIV32_varQ(a, num11, 31));
				num9 = 1073741824 - Inlines.silk_SMMUL(num12, num12);
				num9 = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(num7, num9), 2);
				if (num9 <= minInvGain_Q30)
				{
					num10 = 1073741824 - Inlines.silk_DIV32_varQ(minInvGain_Q30, num7, 30);
					num12 = Inlines.silk_SQRT_APPROX(num10);
					num12 = Inlines.silk_RSHIFT32(num12 + Inlines.silk_DIV32(num10, num12), 1);
					num12 = Inlines.silk_LSHIFT32(num12, 16);
					if (a < 0)
					{
						num12 = -num12;
					}
					num7 = minInvGain_Q30;
					num8 = 1;
				}
				else
				{
					num7 = num9;
				}
				for (int l = 0; l < j + 1 >> 1; l++)
				{
					num9 = array3[l];
					num10 = array3[j - l - 1];
					array3[l] = Inlines.silk_ADD_LSHIFT32(num9, Inlines.silk_SMMUL(num10, num12), 1);
					array3[j - l - 1] = Inlines.silk_ADD_LSHIFT32(num10, Inlines.silk_SMMUL(num9, num12), 1);
				}
				array3[j] = Inlines.silk_RSHIFT32(num12, 6);
				if (num8 != 0)
				{
					for (int l = j + 1; l < D; l++)
					{
						array3[l] = 0;
					}
					break;
				}
				for (int l = 0; l <= j + 1; l++)
				{
					num9 = array4[l];
					num10 = array5[j - l + 1];
					array4[l] = Inlines.silk_ADD_LSHIFT32(num9, Inlines.silk_SMMUL(num10, num12), 1);
					array5[j - l + 1] = Inlines.silk_ADD_LSHIFT32(num10, Inlines.silk_SMMUL(num9, num12), 1);
				}
			}
			if (num8 != 0)
			{
				for (int l = 0; l < D; l++)
				{
					A_Q16[l] = -Inlines.silk_RSHIFT_ROUND(array3[l], 9);
				}
				if (num3 > 0)
				{
					for (int i = 0; i < nb_subfr; i++)
					{
						int num5 = x_ptr + i * subfr_length;
						num4 -= (int)Inlines.silk_RSHIFT64(Inlines.silk_inner_prod16_aligned_64(x, num5, x, num5, D), num3);
					}
				}
				else
				{
					for (int i = 0; i < nb_subfr; i++)
					{
						int num5 = x_ptr + i * subfr_length;
						num4 -= Inlines.silk_LSHIFT32(Inlines.silk_inner_prod_self(x, num5, D), -num3);
					}
				}
				res_nrg.Val = Inlines.silk_LSHIFT(Inlines.silk_SMMUL(num7, num4), 2);
				res_nrg_Q.Val = -num3;
			}
			else
			{
				int num11 = array4[0];
				int num9 = 65536;
				for (int l = 0; l < D; l++)
				{
					int c = Inlines.silk_RSHIFT_ROUND(array3[l], 9);
					num11 = Inlines.silk_SMLAWW(num11, array4[l + 1], c);
					num9 = Inlines.silk_SMLAWW(num9, c, c);
					A_Q16[l] = -c;
				}
				res_nrg.Val = Inlines.silk_SMLAWW(num11, Inlines.silk_SMMUL(42950, num4), -num9);
				res_nrg_Q.Val = -num3;
			}
		}
	}
	internal static class BWExpander
	{
		internal static void silk_bwexpander_32(int[] ar, int d, int chirp_Q16)
		{
			int b = chirp_Q16 - 65536;
			for (int i = 0; i < d - 1; i++)
			{
				ar[i] = Inlines.silk_SMULWW(chirp_Q16, ar[i]);
				chirp_Q16 += Inlines.silk_RSHIFT_ROUND(Inlines.silk_MUL(chirp_Q16, b), 16);
			}
			ar[d - 1] = Inlines.silk_SMULWW(chirp_Q16, ar[d - 1]);
		}

		internal static void silk_bwexpander(short[] ar, int d, int chirp_Q16)
		{
			int b = chirp_Q16 - 65536;
			for (int i = 0; i < d - 1; i++)
			{
				ar[i] = (short)Inlines.silk_RSHIFT_ROUND(Inlines.silk_MUL(chirp_Q16, ar[i]), 16);
				chirp_Q16 += Inlines.silk_RSHIFT_ROUND(Inlines.silk_MUL(chirp_Q16, b), 16);
			}
			ar[d - 1] = (short)Inlines.silk_RSHIFT_ROUND(Inlines.silk_MUL(chirp_Q16, ar[d - 1]), 16);
		}
	}
	internal static class CNG
	{
		internal static void silk_CNG_exc(Span<int> exc_Q10, int exc_Q10_ptr, int[] exc_buf_Q14, int Gain_Q16, int length, ref int rand_seed)
		{
			int num;
			for (num = 255; num > length; num = Inlines.silk_RSHIFT(num, 1))
			{
			}
			int num2 = rand_seed;
			for (int i = exc_Q10_ptr; i < exc_Q10_ptr + length; i++)
			{
				num2 = Inlines.silk_RAND(num2);
				int num3 = Inlines.silk_RSHIFT(num2, 24) & num;
				exc_Q10[i] = (short)Inlines.silk_SAT16(Inlines.silk_SMULWW(exc_buf_Q14[num3], Gain_Q16 >> 4));
			}
			rand_seed = num2;
		}

		internal static void silk_CNG_Reset(SilkChannelDecoder psDec)
		{
			int num = Inlines.silk_DIV32_16(32767, (short)(psDec.LPC_order + 1));
			int num2 = 0;
			for (int i = 0; i < psDec.LPC_order; i++)
			{
				num2 += num;
				psDec.sCNG.CNG_smth_NLSF_Q15[i] = (short)num2;
			}
			psDec.sCNG.CNG_smth_Gain_Q16 = 0;
			psDec.sCNG.rand_seed = 3176576;
		}

		internal static void silk_CNG(SilkChannelDecoder psDec, SilkDecoderControl psDecCtrl, Span<short> frame, int frame_ptr, int length)
		{
			short[] array = new short[psDec.LPC_order];
			CNGState sCNG = psDec.sCNG;
			if (psDec.fs_kHz != sCNG.fs_kHz)
			{
				silk_CNG_Reset(psDec);
				sCNG.fs_kHz = psDec.fs_kHz;
			}
			if (psDec.lossCnt == 0 && psDec.prevSignalType == 0)
			{
				for (int i = 0; i < psDec.LPC_order; i++)
				{
					sCNG.CNG_smth_NLSF_Q15[i] += (short)Inlines.silk_SMULWB(psDec.prevNLSF_Q15[i] - sCNG.CNG_smth_NLSF_Q15[i], 16348);
				}
				int num = 0;
				for (int i = 0; i < psDec.nb_subfr; i++)
				{
					if (psDecCtrl.Gains_Q16[i] > num)
					{
						num = psDecCtrl.Gains_Q16[i];
					}
				}
				Arrays.MemMoveInt(sCNG.CNG_exc_buf_Q14, 0, psDec.subfr_length, (psDec.nb_subfr - 1) * psDec.subfr_length);
				for (int i = 0; i < psDec.nb_subfr; i++)
				{
					sCNG.CNG_smth_Gain_Q16 += Inlines.silk_SMULWB(psDecCtrl.Gains_Q16[i] - sCNG.CNG_smth_Gain_Q16, 4634);
				}
			}
			if (psDec.lossCnt != 0)
			{
				int[] array2 = new int[length + 16];
				int num2 = Inlines.silk_SMULWW(psDec.sPLC.randScale_Q14, psDec.sPLC.prevGain_Q16[1]);
				if (num2 >= 2097152 || sCNG.CNG_smth_Gain_Q16 > 8388608)
				{
					num2 = Inlines.silk_SMULTT(num2, num2);
					num2 = Inlines.silk_SUB_LSHIFT32(Inlines.silk_SMULTT(sCNG.CNG_smth_Gain_Q16, sCNG.CNG_smth_Gain_Q16), num2, 5);
					num2 = Inlines.silk_LSHIFT32(Inlines.silk_SQRT_APPROX(num2), 16);
				}
				else
				{
					num2 = Inlines.silk_SMULWW(num2, num2);
					num2 = Inlines.silk_SUB_LSHIFT32(Inlines.silk_SMULWW(sCNG.CNG_smth_Gain_Q16, sCNG.CNG_smth_Gain_Q16), num2, 5);
					num2 = Inlines.silk_LSHIFT32(Inlines.silk_SQRT_APPROX(num2), 8);
				}
				silk_CNG_exc(array2, 16, sCNG.CNG_exc_buf_Q14, num2, length, ref sCNG.rand_seed);
				NLSF.silk_NLSF2A(array, sCNG.CNG_smth_NLSF_Q15, psDec.LPC_order);
				Arrays.MemCopy(sCNG.CNG_synth_state, 0, array2, 0, 16);
				for (int i = 0; i < length; i++)
				{
					int num3 = 16 + i;
					int a = Inlines.silk_RSHIFT(psDec.LPC_order, 1);
					a = Inlines.silk_SMLAWB(a, array2[num3 - 1], array[0]);
					a = Inlines.silk_SMLAWB(a, array2[num3 - 2], array[1]);
					a = Inlines.silk_SMLAWB(a, array2[num3 - 3], array[2]);
					a = Inlines.silk_SMLAWB(a, array2[num3 - 4], array[3]);
					a = Inlines.silk_SMLAWB(a, array2[num3 - 5], array[4]);
					a = Inlines.silk_SMLAWB(a, array2[num3 - 6], array[5]);
					a = Inlines.silk_SMLAWB(a, array2[num3 - 7], array[6]);
					a = Inlines.silk_SMLAWB(a, array2[num3 - 8], array[7]);
					a = Inlines.silk_SMLAWB(a, array2[num3 - 9], array[8]);
					a = Inlines.silk_SMLAWB(a, array2[num3 - 10], array[9]);
					if (psDec.LPC_order == 16)
					{
						a = Inlines.silk_SMLAWB(a, array2[num3 - 11], array[10]);
						a = Inlines.silk_SMLAWB(a, array2[num3 - 12], array[11]);
						a = Inlines.silk_SMLAWB(a, array2[num3 - 13], array[12]);
						a = Inlines.silk_SMLAWB(a, array2[num3 - 14], array[13]);
						a = Inlines.silk_SMLAWB(a, array2[num3 - 15], array[14]);
						a = Inlines.silk_SMLAWB(a, array2[num3 - 16], array[15]);
					}
					array2[num3] = Inlines.silk_ADD_LSHIFT(array2[num3], a, 4);
					frame[frame_ptr + i] = Inlines.silk_ADD_SAT16(frame[frame_ptr + i], (short)Inlines.silk_RSHIFT_ROUND(array2[num3], 10));
				}
				Arrays.MemCopy(array2, length, sCNG.CNG_synth_state, 0, 16);
			}
			else
			{
				Arrays.MemSetInt(sCNG.CNG_synth_state, 0, psDec.LPC_order);
			}
		}
	}
	internal static class CodeSigns
	{
		private static int silk_enc_map(int a)
		{
			return Inlines.silk_RSHIFT(a, 15) + 1;
		}

		private static int silk_dec_map(int a)
		{
			return Inlines.silk_LSHIFT(a, 1) - 1;
		}

		internal static void silk_encode_signs(EntropyCoder psRangeEnc, Span<byte> encodedData, Span<sbyte> pulses, int length, int signalType, int quantOffsetType, int[] sum_pulses)
		{
			byte[] array = new byte[2];
			byte[] silk_sign_iCDF = Tables.silk_sign_iCDF;
			array[1] = 0;
			int num = 0;
			int num2 = Inlines.silk_SMULBB(7, Inlines.silk_ADD_LSHIFT(quantOffsetType, signalType, 1));
			int num3 = num2;
			length = Inlines.silk_RSHIFT(length + 8, 4);
			for (num2 = 0; num2 < length; num2++)
			{
				int num4 = sum_pulses[num2];
				if (num4 > 0)
				{
					array[0] = silk_sign_iCDF[num3 + Inlines.silk_min(num4 & 0x1F, 6)];
					for (int i = num; i < num + 16; i++)
					{
						if (pulses[i] != 0)
						{
							psRangeEnc.enc_icdf(encodedData, silk_enc_map(pulses[i]), array, 8u);
						}
					}
				}
				num += 16;
			}
		}

		internal static void silk_decode_signs(EntropyCoder psRangeDec, ReadOnlySpan<byte> encodedData, short[] pulses, int length, int signalType, int quantOffsetType, int[] sum_pulses)
		{
			byte[] array = new byte[2];
			byte[] silk_sign_iCDF = Tables.silk_sign_iCDF;
			array[1] = 0;
			int num = 0;
			int num2 = Inlines.silk_SMULBB(7, Inlines.silk_ADD_LSHIFT(quantOffsetType, signalType, 1));
			int num3 = num2;
			length = Inlines.silk_RSHIFT(length + 8, 4);
			for (num2 = 0; num2 < length; num2++)
			{
				int num4 = sum_pulses[num2];
				if (num4 > 0)
				{
					array[0] = silk_sign_iCDF[num3 + Inlines.silk_min(num4 & 0x1F, 6)];
					for (int i = 0; i < 16; i++)
					{
						if (pulses[num + i] > 0)
						{
							pulses[num + i] *= (short)silk_dec_map(psRangeDec.dec_icdf(encodedData, array, 8u));
						}
					}
				}
				num += 16;
			}
		}
	}
	internal static class CorrelateMatrix
	{
		internal static void silk_corrVector(short[] x, int x_ptr, short[] t, int t_ptr, int L, int order, int[] Xt, int rshifts)
		{
			int num = x_ptr + order - 1;
			if (rshifts > 0)
			{
				for (int i = 0; i < order; i++)
				{
					int num2 = 0;
					for (int j = 0; j < L; j++)
					{
						num2 += Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[num + j], t[t_ptr + j]), rshifts);
					}
					Xt[i] = num2;
					num--;
				}
			}
			else
			{
				for (int i = 0; i < order; i++)
				{
					Xt[i] = Inlines.silk_inner_prod(x, num, t, t_ptr, L);
					num--;
				}
			}
		}

		internal static void silk_corrMatrix(short[] x, int x_ptr, int L, int order, int head_room, int[] XX, int XX_ptr, BoxedValueInt rshifts)
		{
			SumSqrShift.silk_sum_sqr_shift(out var energy, out var shift, x, x_ptr, L + order - 1);
			int num = Inlines.silk_max(head_room - Inlines.silk_CLZ32(energy), 0);
			energy = Inlines.silk_RSHIFT32(energy, num);
			shift += num;
			for (int i = x_ptr; i < x_ptr + order - 1; i++)
			{
				energy -= Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[i], x[i]), shift);
			}
			if (shift < rshifts.Val)
			{
				energy = Inlines.silk_RSHIFT32(energy, rshifts.Val - shift);
				shift = rshifts.Val;
			}
			Inlines.MatrixSet(XX, XX_ptr, 0, 0, order, energy);
			int num2 = x_ptr + order - 1;
			for (int j = 1; j < order; j++)
			{
				energy = Inlines.silk_SUB32(energy, Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[num2 + L - j], x[num2 + L - j]), shift));
				energy = Inlines.silk_ADD32(energy, Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[num2 - j], x[num2 - j]), shift));
				Inlines.MatrixSet(XX, XX_ptr, j, j, order, energy);
			}
			int num3 = x_ptr + order - 2;
			if (shift > 0)
			{
				for (int k = 1; k < order; k++)
				{
					energy = 0;
					for (int i = 0; i < L; i++)
					{
						energy += Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[num2 + i], x[num3 + i]), shift);
					}
					Inlines.MatrixSet(XX, XX_ptr, k, 0, order, energy);
					Inlines.MatrixSet(XX, XX_ptr, 0, k, order, energy);
					for (int j = 1; j < order - k; j++)
					{
						energy = Inlines.silk_SUB32(energy, Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[num2 + L - j], x[num3 + L - j]), shift));
						energy = Inlines.silk_ADD32(energy, Inlines.silk_RSHIFT32(Inlines.silk_SMULBB(x[num2 - j], x[num3 - j]), shift));
						Inlines.MatrixSet(XX, XX_ptr, k + j, j, order, energy);
						Inlines.MatrixSet(XX, XX_ptr, j, k + j, order, energy);
					}
					num3--;
				}
			}
			else
			{
				for (int k = 1; k < order; k++)
				{
					energy = Inlines.silk_inner_prod(x, num2, x, num3, L);
					Inlines.MatrixSet(XX, XX_ptr, k, 0, order, energy);
					Inlines.MatrixSet(XX, XX_ptr, 0, k, order, energy);
					for (int j = 1; j < order - k; j++)
					{
						energy = Inlines.silk_SUB32(energy, Inlines.silk_SMULBB(x[num2 + L - j], x[num3 + L - j]));
						energy = Inlines.silk_SMLABB(energy, x[num2 - j], x[num3 - j]);
						Inlines.MatrixSet(XX, XX_ptr, k + j, j, order, energy);
						Inlines.MatrixSet(XX, XX_ptr, j, k + j, order, energy);
					}
					num3--;
				}
			}
			rshifts.Val = shift;
		}
	}
	internal static class DecodeAPI
	{
		internal static int silk_InitDecoder(SilkDecoder decState)
		{
			decState.Reset();
			int result = SilkError.SILK_NO_ERROR;
			SilkChannelDecoder[] channel_state = decState.channel_state;
			for (int i = 0; i < 2; i++)
			{
				result = channel_state[i].silk_init_decoder();
			}
			decState.sStereo.Reset();
			decState.prev_decode_only_middle = 0;
			return result;
		}

		internal static int silk_Decode(SilkDecoder psDec, DecControlState decControl, ReadOnlySpan<byte> frameData, int lostFlag, int newPacketFlag, EntropyCoder psRangeDec, Span<short> samplesOut, int samplesOut_ptr, out int nSamplesOut)
		{
			int num = 0;
			int num2 = SilkError.SILK_NO_ERROR;
			BoxedValueInt boxedValueInt = new BoxedValueInt();
			int[] array = new int[2];
			int[] array2 = new int[2];
			SilkChannelDecoder[] channel_state = psDec.channel_state;
			nSamplesOut = 0;
			if (newPacketFlag != 0)
			{
				for (int i = 0; i < decControl.nChannelsInternal; i++)
				{
					channel_state[i].nFramesDecoded = 0;
				}
			}
			if (decControl.nChannelsInternal > psDec.nChannelsInternal)
			{
				num2 += channel_state[1].silk_init_decoder();
			}
			int num3 = ((decControl.nChannelsInternal == 1 && psDec.nChannelsInternal == 2 && decControl.internalSampleRate == 1000 * channel_state[0].fs_kHz) ? 1 : 0);
			if (channel_state[0].nFramesDecoded == 0)
			{
				for (int i = 0; i < decControl.nChannelsInternal; i++)
				{
					if (decControl.payloadSize_ms == 0)
					{
						channel_state[i].nFramesPerPacket = 1;
						channel_state[i].nb_subfr = 2;
					}
					else if (decControl.payloadSize_ms == 10)
					{
						channel_state[i].nFramesPerPacket = 1;
						channel_state[i].nb_subfr = 2;
					}
					else if (decControl.payloadSize_ms == 20)
					{
						channel_state[i].nFramesPerPacket = 1;
						channel_state[i].nb_subfr = 4;
					}
					else if (decControl.payloadSize_ms == 40)
					{
						channel_state[i].nFramesPerPacket = 2;
						channel_state[i].nb_subfr = 4;
					}
					else
					{
						if (decControl.payloadSize_ms != 60)
						{
							return SilkError.SILK_DEC_INVALID_FRAME_SIZE;
						}
						channel_state[i].nFramesPerPacket = 3;
						channel_state[i].nb_subfr = 4;
					}
					int num4 = (decControl.internalSampleRate >> 10) + 1;
					if (num4 != 8 && num4 != 12 && num4 != 16)
					{
						return SilkError.SILK_DEC_INVALID_SAMPLING_FREQUENCY;
					}
					num2 += channel_state[i].silk_decoder_set_fs(num4, decControl.API_sampleRate);
				}
			}
			if (decControl.nChannelsAPI == 2 && decControl.nChannelsInternal == 2 && (psDec.nChannelsAPI == 1 || psDec.nChannelsInternal == 1))
			{
				Arrays.MemSetShort(psDec.sStereo.pred_prev_Q13, 0, 2);
				Arrays.MemSetShort(psDec.sStereo.sSide, 0, 2);
				channel_state[1].resampler_state.Assign(channel_state[0].resampler_state);
			}
			psDec.nChannelsAPI = decControl.nChannelsAPI;
			psDec.nChannelsInternal = decControl.nChannelsInternal;
			if (decControl.API_sampleRate > 48000 || decControl.API_sampleRate < 8000)
			{
				return SilkError.SILK_DEC_INVALID_SAMPLING_FREQUENCY;
			}
			if (lostFlag != 1 && channel_state[0].nFramesDecoded == 0)
			{
				for (int i = 0; i < decControl.nChannelsInternal; i++)
				{
					for (int j = 0; j < channel_state[i].nFramesPerPacket; j++)
					{
						channel_state[i].VAD_flags[j] = psRangeDec.dec_bit_logp(frameData, 1u);
					}
					channel_state[i].LBRR_flag = psRangeDec.dec_bit_logp(frameData, 1u);
				}
				for (int i = 0; i < decControl.nChannelsInternal; i++)
				{
					Arrays.MemSetInt(channel_state[i].LBRR_flags, 0, 3);
					if (channel_state[i].LBRR_flag == 0)
					{
						continue;
					}
					if (channel_state[i].nFramesPerPacket == 1)
					{
						channel_state[i].LBRR_flags[0] = 1;
						continue;
					}
					int a = psRangeDec.dec_icdf(frameData, Tables.silk_LBRR_flags_iCDF_ptr[channel_state[i].nFramesPerPacket - 2], 8u) + 1;
					for (int j = 0; j < channel_state[i].nFramesPerPacket; j++)
					{
						channel_state[i].LBRR_flags[j] = Inlines.silk_RSHIFT(a, j) & 1;
					}
				}
				if (lostFlag == 0)
				{
					for (int j = 0; j < channel_state[0].nFramesPerPacket; j++)
					{
						for (int i = 0; i < decControl.nChannelsInternal; i++)
						{
							if (channel_state[i].LBRR_flags[j] == 0)
							{
								continue;
							}
							short[] pulses = new short[320];
							if (decControl.nChannelsInternal == 2 && i == 0)
							{
								Stereo.silk_stereo_decode_pred(psRangeDec, frameData, array2);
								if (channel_state[1].LBRR_flags[j] == 0)
								{
									BoxedValueInt boxedValueInt2 = new BoxedValueInt(num);
									Stereo.silk_stereo_decode_mid_only(psRangeDec, frameData, boxedValueInt2);
									num = boxedValueInt2.Val;
								}
							}
							DecodeIndices.silk_decode_indices(condCoding: (j > 0 && channel_state[i].LBRR_flags[j - 1] != 0) ? 2 : 0, psDec: channel_state[i], psRangeDec: psRangeDec, frameData: frameData, FrameIndex: j, decode_LBRR: 1);
							DecodePulses.silk_decode_pulses(psRangeDec, frameData, pulses, channel_state[i].indices.signalType, channel_state[i].indices.quantOffsetType, channel_state[i].frame_length);
						}
					}
				}
			}
			if (decControl.nChannelsInternal == 2)
			{
				if (lostFlag == 0 || (lostFlag == 2 && channel_state[0].LBRR_flags[channel_state[0].nFramesDecoded] == 1))
				{
					Stereo.silk_stereo_decode_pred(psRangeDec, frameData, array2);
					if ((lostFlag == 0 && channel_state[1].VAD_flags[channel_state[0].nFramesDecoded] == 0) || (lostFlag == 2 && channel_state[1].LBRR_flags[channel_state[0].nFramesDecoded] == 0))
					{
						BoxedValueInt boxedValueInt3 = new BoxedValueInt(num);
						Stereo.silk_stereo_decode_mid_only(psRangeDec, frameData, boxedValueInt3);
						num = boxedValueInt3.Val;
					}
					else
					{
						num = 0;
					}
				}
				else
				{
					for (int i = 0; i < 2; i++)
					{
						array2[i] = psDec.sStereo.pred_prev_Q13[i];
					}
				}
			}
			if (decControl.nChannelsInternal == 2 && num == 0 && psDec.prev_decode_only_middle == 1)
			{
				Arrays.MemSetShort(psDec.channel_state[1].outBuf, 0, 480);
				Arrays.MemSetInt(psDec.channel_state[1].sLPC_Q14_buf, 0, 16);
				psDec.channel_state[1].lagPrev = 100;
				psDec.channel_state[1].LastGainIndex = 10;
				psDec.channel_state[1].prevSignalType = 0;
				psDec.channel_state[1].first_frame_after_reset = 1;
			}
			int num5 = ((decControl.internalSampleRate * decControl.nChannelsInternal < decControl.API_sampleRate * decControl.nChannelsAPI) ? 1 : 0);
			Span<short> span;
			if (num5 != 0)
			{
				span = samplesOut;
				array[0] = samplesOut_ptr;
				array[1] = samplesOut_ptr + channel_state[0].frame_length + 2;
			}
			else
			{
				span = new short[decControl.nChannelsInternal * (channel_state[0].frame_length + 2)];
				array[0] = 0;
				array[1] = channel_state[0].frame_length + 2;
			}
			int num6 = ((lostFlag != 0) ? ((psDec.prev_decode_only_middle == 0 || (decControl.nChannelsInternal == 2 && lostFlag == 2 && channel_state[1].LBRR_flags[channel_state[1].nFramesDecoded] == 1)) ? 1 : 0) : ((num == 0) ? 1 : 0));
			for (int i = 0; i < decControl.nChannelsInternal; i++)
			{
				if (i == 0 || num6 != 0)
				{
					int num7 = channel_state[0].nFramesDecoded - i;
					int condCoding2 = ((num7 > 0) ? ((lostFlag == 2) ? ((channel_state[i].LBRR_flags[num7 - 1] != 0) ? 2 : 0) : ((i > 0 && psDec.prev_decode_only_middle != 0) ? 1 : 2)) : 0);
					num2 += channel_state[i].silk_decode_frame(psRangeDec, frameData, span, array[i] + 2, boxedValueInt, lostFlag, condCoding2);
				}
				else
				{
					Arrays.MemSetWithOffset<short>(span, 0, array[i] + 2, boxedValueInt.Val);
				}
				channel_state[i].nFramesDecoded++;
			}
			if (decControl.nChannelsAPI == 2 && decControl.nChannelsInternal == 2)
			{
				Stereo.silk_stereo_MS_to_LR(psDec.sStereo, span, array[0], span, array[1], array2, channel_state[0].fs_kHz, boxedValueInt.Val);
			}
			else
			{
				psDec.sStereo.sMid.AsSpan(0, 2).CopyTo(span.Slice(array[0]));
				span.Slice(array[0] + boxedValueInt.Val, 2).CopyTo(psDec.sStereo.sMid);
			}
			nSamplesOut = Inlines.silk_DIV32(boxedValueInt.Val * decControl.API_sampleRate, Inlines.silk_SMULBB(channel_state[0].fs_kHz, 1000));
			Span<short> output;
			int num8;
			if (decControl.nChannelsAPI == 2)
			{
				output = new short[nSamplesOut];
				num8 = 0;
			}
			else
			{
				output = samplesOut;
				num8 = samplesOut_ptr;
			}
			if (num5 != 0)
			{
				short[] array3 = new short[decControl.nChannelsInternal * (channel_state[0].frame_length + 2)];
				samplesOut.Slice(samplesOut_ptr, decControl.nChannelsInternal * (channel_state[0].frame_length + 2)).CopyTo(array3);
				span = array3;
				array[0] = 0;
				array[1] = channel_state[0].frame_length + 2;
			}
			for (int i = 0; i < Inlines.silk_min(decControl.nChannelsAPI, decControl.nChannelsInternal); i++)
			{
				num2 += Resampler.silk_resampler(channel_state[i].resampler_state, output, num8, span, array[i] + 1, boxedValueInt.Val);
				if (decControl.nChannelsAPI == 2)
				{
					int num9 = samplesOut_ptr + i;
					for (int j = 0; j < nSamplesOut; j++)
					{
						samplesOut[num9 + 2 * j] = output[num8 + j];
					}
				}
			}
			if (decControl.nChannelsAPI == 2 && decControl.nChannelsInternal == 1)
			{
				if (num3 != 0)
				{
					num2 += Resampler.silk_resampler(channel_state[1].resampler_state, output, num8, span, array[0] + 1, boxedValueInt.Val);
					for (int j = 0; j < nSamplesOut; j++)
					{
						samplesOut[samplesOut_ptr + 1 + 2 * j] = output[num8 + j];
					}
				}
				else
				{
					for (int j = 0; j < nSamplesOut; j++)
					{
						samplesOut[samplesOut_ptr + 1 + 2 * j] = samplesOut[samplesOut_ptr + 2 * j];
					}
				}
			}
			if (channel_state[0].prevSignalType == 2)
			{
				int[] array4 = new int[3] { 6, 4, 3 };
				decControl.prevPitchLag = channel_state[0].lagPrev * array4[channel_state[0].fs_kHz - 8 >> 2];
			}
			else
			{
				decControl.prevPitchLag = 0;
			}
			if (lostFlag == 1)
			{
				for (int j = 0; j < psDec.nChannelsInternal; j++)
				{
					psDec.channel_state[j].LastGainIndex = 10;
				}
			}
			else
			{
				psDec.prev_decode_only_middle = num;
			}
			return num2;
		}
	}
	internal static class DecodeCore
	{
		internal static void silk_decode_core(SilkChannelDecoder psDec, SilkDecoderControl psDecCtrl, Span<short> xq, int xq_ptr, short[] pulses)
		{
			int num = 0;
			short[] lTPCoef_Q = psDecCtrl.LTPCoef_Q14;
			short[] array = new short[psDec.ltp_mem_length];
			int[] array2 = new int[psDec.ltp_mem_length + psDec.frame_length];
			int[] array3 = new int[psDec.subfr_length];
			int[] array4 = new int[psDec.subfr_length + 16];
			int num2 = Tables.silk_Quantization_Offsets_Q10[psDec.indices.signalType >> 1][psDec.indices.quantOffsetType];
			int num3 = ((psDec.indices.NLSFInterpCoef_Q2 < 4) ? 1 : 0);
			int seed = psDec.indices.Seed;
			for (int i = 0; i < psDec.frame_length; i++)
			{
				seed = Inlines.silk_RAND(seed);
				psDec.exc_Q14[i] = Inlines.silk_LSHIFT(pulses[i], 14);
				if (psDec.exc_Q14[i] > 0)
				{
					psDec.exc_Q14[i] -= 1280;
				}
				else if (psDec.exc_Q14[i] < 0)
				{
					psDec.exc_Q14[i] += 1280;
				}
				psDec.exc_Q14[i] += num2 << 4;
				if (seed < 0)
				{
					psDec.exc_Q14[i] = -psDec.exc_Q14[i];
				}
				seed = Inlines.silk_ADD32_ovflw(seed, pulses[i]);
			}
			Arrays.MemCopy(psDec.sLPC_Q14_buf, 0, array4, 0, 16);
			int num4 = 0;
			int num5 = xq_ptr;
			int num6 = psDec.ltp_mem_length;
			for (int j = 0; j < psDec.nb_subfr; j++)
			{
				int[] array5 = array3;
				int num7 = 0;
				short[] array6 = psDecCtrl.PredCoef_Q12[j >> 1];
				int num8 = j * 5;
				int num9 = psDec.indices.signalType;
				int b = Inlines.silk_RSHIFT(psDecCtrl.Gains_Q16[j], 6);
				int a = Inlines.silk_INVERSE32_varQ(psDecCtrl.Gains_Q16[j], 47);
				int num10;
				if (psDecCtrl.Gains_Q16[j] != psDec.prev_gain_Q16)
				{
					num10 = Inlines.silk_DIV32_varQ(psDec.prev_gain_Q16, psDecCtrl.Gains_Q16[j], 16);
					for (int i = 0; i < 16; i++)
					{
						array4[i] = Inlines.silk_SMULWW(num10, array4[i]);
					}
				}
				else
				{
					num10 = 65536;
				}
				psDec.prev_gain_Q16 = psDecCtrl.Gains_Q16[j];
				if (psDec.lossCnt != 0 && psDec.prevSignalType == 2 && psDec.indices.signalType != 2 && j < 2)
				{
					Arrays.MemSetWithOffset(lTPCoef_Q, (short)0, num8, 5);
					lTPCoef_Q[num8 + 2] = 4096;
					num9 = 2;
					psDecCtrl.pitchL[j] = psDec.lagPrev;
				}
				if (num9 == 2)
				{
					num = psDecCtrl.pitchL[j];
					if (j == 0 || (j == 2 && num3 != 0))
					{
						int num11 = psDec.ltp_mem_length - num - psDec.LPC_order - 2;
						if (j == 2)
						{
							xq.Slice(xq_ptr, 2 * psDec.subfr_length).CopyTo(psDec.outBuf.AsSpan(psDec.ltp_mem_length));
						}
						Filters.silk_LPC_analysis_filter(array, num11, psDec.outBuf, num11 + j * psDec.subfr_length, array6, 0, psDec.ltp_mem_length - num11, psDec.LPC_order);
						if (j == 0)
						{
							a = Inlines.silk_LSHIFT(Inlines.silk_SMULWB(a, psDecCtrl.LTP_scale_Q14), 2);
						}
						for (int i = 0; i < num + 2; i++)
						{
							array2[num6 - i - 1] = Inlines.silk_SMULWB(a, array[psDec.ltp_mem_length - i - 1]);
						}
					}
					else if (num10 != 65536)
					{
						for (int i = 0; i < num + 2; i++)
						{
							array2[num6 - i - 1] = Inlines.silk_SMULWW(num10, array2[num6 - i - 1]);
						}
					}
				}
				if (num9 == 2)
				{
					int num12 = num6 - num + 2;
					for (int i = 0; i < psDec.subfr_length; i++)
					{
						int a2 = 2;
						a2 = Inlines.silk_SMLAWB(a2, array2[num12], lTPCoef_Q[num8]);
						a2 = Inlines.silk_SMLAWB(a2, array2[num12 - 1], lTPCoef_Q[num8 + 1]);
						a2 = Inlines.silk_SMLAWB(a2, array2[num12 - 2], lTPCoef_Q[num8 + 2]);
						a2 = Inlines.silk_SMLAWB(a2, array2[num12 - 3], lTPCoef_Q[num8 + 3]);
						a2 = Inlines.silk_SMLAWB(a2, array2[num12 - 4], lTPCoef_Q[num8 + 4]);
						num12++;
						array5[num7 + i] = Inlines.silk_ADD_LSHIFT32(psDec.exc_Q14[num4 + i], a2, 1);
						array2[num6] = Inlines.silk_LSHIFT(array5[num7 + i], 1);
						num6++;
					}
				}
				else
				{
					array5 = psDec.exc_Q14;
					num7 = num4;
				}
				for (int i = 0; i < psDec.subfr_length; i++)
				{
					int a3 = Inlines.silk_RSHIFT(psDec.LPC_order, 1);
					a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 1], array6[0]);
					a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 2], array6[1]);
					a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 3], array6[2]);
					a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 4], array6[3]);
					a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 5], array6[4]);
					a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 6], array6[5]);
					a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 7], array6[6]);
					a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 8], array6[7]);
					a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 9], array6[8]);
					a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 10], array6[9]);
					if (psDec.LPC_order == 16)
					{
						a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 11], array6[10]);
						a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 12], array6[11]);
						a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 13], array6[12]);
						a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 14], array6[13]);
						a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 15], array6[14]);
						a3 = Inlines.silk_SMLAWB(a3, array4[16 + i - 16], array6[15]);
					}
					array4[16 + i] = Inlines.silk_ADD_LSHIFT32(array5[num7 + i], a3, 4);
					xq[num5 + i] = (short)Inlines.silk_SAT16(Inlines.silk_RSHIFT_ROUND(Inlines.silk_SMULWW(array4[16 + i], b), 8));
				}
				Arrays.MemCopy(array4, psDec.subfr_length, array4, 0, 16);
				num4 += psDec.subfr_length;
				num5 += psDec.subfr_length;
			}
			Arrays.MemCopy(array4, 0, psDec.sLPC_Q14_buf, 0, 16);
		}
	}
	internal static class DecodeIndices
	{
		internal static void silk_decode_indices(SilkChannelDecoder psDec, EntropyCoder psRangeDec, ReadOnlySpan<byte> frameData, int FrameIndex, int decode_LBRR, int condCoding)
		{
			short[] array = new short[psDec.LPC_order];
			byte[] array2 = new byte[psDec.LPC_order];
			int num = ((decode_LBRR == 0 && psDec.VAD_flags[FrameIndex] == 0) ? psRangeDec.dec_icdf(frameData, Tables.silk_type_offset_no_VAD_iCDF, 8u) : (psRangeDec.dec_icdf(frameData, Tables.silk_type_offset_VAD_iCDF, 8u) + 2));
			psDec.indices.signalType = (sbyte)Inlines.silk_RSHIFT(num, 1);
			psDec.indices.quantOffsetType = (sbyte)(num & 1);
			if (condCoding == 2)
			{
				psDec.indices.GainsIndices[0] = (sbyte)psRangeDec.dec_icdf(frameData, Tables.silk_delta_gain_iCDF, 8u);
			}
			else
			{
				psDec.indices.GainsIndices[0] = (sbyte)Inlines.silk_LSHIFT(psRangeDec.dec_icdf(frameData, Tables.silk_gain_iCDF[psDec.indices.signalType], 8u), 3);
				psDec.indices.GainsIndices[0] += (sbyte)psRangeDec.dec_icdf(frameData, Tables.silk_uniform8_iCDF, 8u);
			}
			for (int i = 1; i < psDec.nb_subfr; i++)
			{
				psDec.indices.GainsIndices[i] = (sbyte)psRangeDec.dec_icdf(frameData, Tables.silk_delta_gain_iCDF, 8u);
			}
			psDec.indices.NLSFIndices[0] = (sbyte)psRangeDec.dec_icdf(frameData, psDec.psNLSF_CB.CB1_iCDF, (psDec.indices.signalType >> 1) * psDec.psNLSF_CB.nVectors, 8u);
			NLSF.silk_NLSF_unpack(array, array2, psDec.psNLSF_CB, psDec.indices.NLSFIndices[0]);
			for (int i = 0; i < psDec.psNLSF_CB.order; i++)
			{
				num = psRangeDec.dec_icdf(frameData, psDec.psNLSF_CB.ec_iCDF, array[i], 8u);
				switch (num)
				{
				case 0:
					num -= psRangeDec.dec_icdf(frameData, Tables.silk_NLSF_EXT_iCDF, 8u);
					break;
				case 8:
					num += psRangeDec.dec_icdf(frameData, Tables.silk_NLSF_EXT_iCDF, 8u);
					break;
				}
				psDec.indices.NLSFIndices[i + 1] = (sbyte)(num - 4);
			}
			if (psDec.nb_subfr == 4)
			{
				psDec.indices.NLSFInterpCoef_Q2 = (sbyte)psRangeDec.dec_icdf(frameData, Tables.silk_NLSF

Mods/Facepunch.Steamworks.Win64.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Steamworks.Data;
using Steamworks.Ugc;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.6", FrameworkDisplayName = ".NET Framework 4.6")]
[assembly: AssemblyCompany("Garry Newman")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Facepunch.Steamworks.Win64")]
[assembly: AssemblyTitle("Facepunch.Steamworks.Win64")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
}
namespace Steamworks
{
	internal struct CallResult<T> : INotifyCompletion where T : struct, ICallbackData
	{
		private SteamAPICall_t call;

		private ISteamUtils utils;

		private bool server;

		public bool IsCompleted
		{
			get
			{
				bool pbFailed = false;
				if (utils.IsAPICallCompleted(call, ref pbFailed) || pbFailed)
				{
					return true;
				}
				return false;
			}
		}

		public CallResult(SteamAPICall_t call, bool server)
		{
			this.call = call;
			this.server = server;
			utils = (server ? SteamSharedClass<SteamUtils>.InterfaceServer : SteamSharedClass<SteamUtils>.InterfaceClient) as ISteamUtils;
			if (utils == null)
			{
				utils = SteamSharedClass<SteamUtils>.Interface as ISteamUtils;
			}
		}

		public void OnCompleted(Action continuation)
		{
			Dispatch.OnCallComplete<T>(call, continuation, server);
		}

		public T? GetResult()
		{
			bool pbFailed = false;
			if (!utils.IsAPICallCompleted(call, ref pbFailed) || pbFailed)
			{
				return null;
			}
			T val = default(T);
			int dataSize = val.DataSize;
			IntPtr intPtr = Marshal.AllocHGlobal(dataSize);
			try
			{
				if (!utils.GetAPICallResult(call, intPtr, dataSize, (int)val.CallbackType, ref pbFailed) || pbFailed)
				{
					Dispatch.OnDebugCallback?.Invoke(val.CallbackType, "!GetAPICallResult or failed", server);
					return null;
				}
				Dispatch.OnDebugCallback?.Invoke(val.CallbackType, Dispatch.CallbackToString(val.CallbackType, intPtr, dataSize), server);
				return (T)Marshal.PtrToStructure(intPtr, typeof(T));
			}
			finally
			{
				Marshal.FreeHGlobal(intPtr);
			}
		}

		internal CallResult<T> GetAwaiter()
		{
			return this;
		}
	}
	internal interface ICallbackData
	{
		CallbackType CallbackType { get; }

		int DataSize { get; }
	}
	public class AuthTicket : IDisposable
	{
		public byte[] Data;

		public uint Handle;

		public void Cancel()
		{
			if (Handle != 0)
			{
				SteamUser.Internal.CancelAuthTicket(Handle);
			}
			Handle = 0u;
			Data = null;
		}

		public void Dispose()
		{
			Cancel();
		}
	}
	public static class Dispatch
	{
		[StructLayout(LayoutKind.Sequential, Pack = 8)]
		internal struct CallbackMsg_t
		{
			public HSteamUser m_hSteamUser;

			public CallbackType Type;

			public IntPtr Data;

			public int DataSize;
		}

		private struct ResultCallback
		{
			public Action continuation;

			public bool server;
		}

		private struct Callback
		{
			public Action<IntPtr> action;

			public bool server;
		}

		public static Action<CallbackType, string, bool> OnDebugCallback;

		public static Action<Exception> OnException;

		private static bool runningFrame = false;

		private static List<Action<IntPtr>> actionsToCall = new List<Action<IntPtr>>();

		private static Dictionary<ulong, ResultCallback> ResultCallbacks = new Dictionary<ulong, ResultCallback>();

		private static Dictionary<CallbackType, List<Callback>> Callbacks = new Dictionary<CallbackType, List<Callback>>();

		internal static HSteamPipe ClientPipe { get; set; }

		internal static HSteamPipe ServerPipe { get; set; }

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl)]
		internal static extern void SteamAPI_ManualDispatch_Init();

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl)]
		internal static extern void SteamAPI_ManualDispatch_RunFrame(HSteamPipe pipe);

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl)]
		[return: MarshalAs(UnmanagedType.I1)]
		internal static extern bool SteamAPI_ManualDispatch_GetNextCallback(HSteamPipe pipe, [In][Out] ref CallbackMsg_t msg);

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl)]
		[return: MarshalAs(UnmanagedType.I1)]
		internal static extern bool SteamAPI_ManualDispatch_FreeLastCallback(HSteamPipe pipe);

		internal static void Init()
		{
			SteamAPI_ManualDispatch_Init();
		}

		internal static void Frame(HSteamPipe pipe)
		{
			if (runningFrame)
			{
				return;
			}
			try
			{
				runningFrame = true;
				SteamAPI_ManualDispatch_RunFrame(pipe);
				SteamNetworkingUtils.OutputDebugMessages();
				CallbackMsg_t msg = default(CallbackMsg_t);
				while (SteamAPI_ManualDispatch_GetNextCallback(pipe, ref msg))
				{
					try
					{
						ProcessCallback(msg, pipe == ServerPipe);
					}
					finally
					{
						SteamAPI_ManualDispatch_FreeLastCallback(pipe);
					}
				}
			}
			catch (Exception obj)
			{
				OnException?.Invoke(obj);
			}
			finally
			{
				runningFrame = false;
			}
		}

		private static void ProcessCallback(CallbackMsg_t msg, bool isServer)
		{
			OnDebugCallback?.Invoke(msg.Type, CallbackToString(msg.Type, msg.Data, msg.DataSize), isServer);
			if (msg.Type == CallbackType.SteamAPICallCompleted)
			{
				ProcessResult(msg);
			}
			else
			{
				if (!Callbacks.TryGetValue(msg.Type, out var value))
				{
					return;
				}
				actionsToCall.Clear();
				foreach (Callback item in value)
				{
					if (item.server == isServer)
					{
						actionsToCall.Add(item.action);
					}
				}
				foreach (Action<IntPtr> item2 in actionsToCall)
				{
					item2(msg.Data);
				}
				actionsToCall.Clear();
			}
		}

		internal static string CallbackToString(CallbackType type, IntPtr data, int expectedsize)
		{
			if (!CallbackTypeFactory.All.TryGetValue(type, out var value))
			{
				return $"[{type} not in sdk]";
			}
			object obj = data.ToType(value);
			if (obj == null)
			{
				return "[null]";
			}
			string text = "";
			FieldInfo[] fields = value.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (fields.Length == 0)
			{
				return "[no fields]";
			}
			int num = fields.Max((FieldInfo x) => x.Name.Length) + 1;
			if (num < 10)
			{
				num = 10;
			}
			FieldInfo[] array = fields;
			foreach (FieldInfo fieldInfo in array)
			{
				int num2 = num - fieldInfo.Name.Length;
				if (num2 < 0)
				{
					num2 = 0;
				}
				text += $"{new string(' ', num2)}{fieldInfo.Name}: {fieldInfo.GetValue(obj)}\n";
			}
			return text.Trim(new char[1] { '\n' });
		}

		private static void ProcessResult(CallbackMsg_t msg)
		{
			SteamAPICallCompleted_t steamAPICallCompleted_t = msg.Data.ToType<SteamAPICallCompleted_t>();
			if (!ResultCallbacks.TryGetValue(steamAPICallCompleted_t.AsyncCall, out var value))
			{
				OnDebugCallback?.Invoke((CallbackType)steamAPICallCompleted_t.Callback, "[no callback waiting/required]", arg3: false);
				return;
			}
			ResultCallbacks.Remove(steamAPICallCompleted_t.AsyncCall);
			value.continuation();
		}

		internal static async void LoopClientAsync()
		{
			while (ClientPipe != 0)
			{
				Frame(ClientPipe);
				await Task.Delay(16);
			}
		}

		internal static async void LoopServerAsync()
		{
			while (ServerPipe != 0)
			{
				Frame(ServerPipe);
				await Task.Delay(32);
			}
		}

		internal static void OnCallComplete<T>(SteamAPICall_t call, Action continuation, bool server) where T : struct, ICallbackData
		{
			ResultCallbacks[call.Value] = new ResultCallback
			{
				continuation = continuation,
				server = server
			};
		}

		internal static void Install<T>(Action<T> p, bool server = false) where T : ICallbackData
		{
			CallbackType callbackType = default(T).CallbackType;
			if (!Callbacks.TryGetValue(callbackType, out var value))
			{
				value = new List<Callback>();
				Callbacks[callbackType] = value;
			}
			value.Add(new Callback
			{
				action = delegate(IntPtr x)
				{
					p(x.ToType<T>());
				},
				server = server
			});
		}

		internal static void ShutdownServer()
		{
			ServerPipe = 0;
			foreach (KeyValuePair<CallbackType, List<Callback>> callback in Callbacks)
			{
				Callbacks[callback.Key].RemoveAll((Callback x) => x.server);
			}
			ResultCallbacks = ResultCallbacks.Where((KeyValuePair<ulong, ResultCallback> x) => !x.Value.server).ToDictionary((KeyValuePair<ulong, ResultCallback> x) => x.Key, (KeyValuePair<ulong, ResultCallback> x) => x.Value);
		}

		internal static void ShutdownClient()
		{
			ClientPipe = 0;
			foreach (KeyValuePair<CallbackType, List<Callback>> callback in Callbacks)
			{
				Callbacks[callback.Key].RemoveAll((Callback x) => !x.server);
			}
			ResultCallbacks = ResultCallbacks.Where((KeyValuePair<ulong, ResultCallback> x) => x.Value.server).ToDictionary((KeyValuePair<ulong, ResultCallback> x) => x.Key, (KeyValuePair<ulong, ResultCallback> x) => x.Value);
		}
	}
	internal static class SteamAPI
	{
		internal static class Native
		{
			[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl)]
			[return: MarshalAs(UnmanagedType.I1)]
			public static extern bool SteamAPI_Init();

			[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl)]
			public static extern void SteamAPI_Shutdown();

			[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl)]
			public static extern HSteamPipe SteamAPI_GetHSteamPipe();

			[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl)]
			[return: MarshalAs(UnmanagedType.I1)]
			public static extern bool SteamAPI_RestartAppIfNecessary(uint unOwnAppID);
		}

		internal static bool Init()
		{
			return Native.SteamAPI_Init();
		}

		internal static void Shutdown()
		{
			Native.SteamAPI_Shutdown();
		}

		internal static HSteamPipe GetHSteamPipe()
		{
			return Native.SteamAPI_GetHSteamPipe();
		}

		internal static bool RestartAppIfNecessary(uint unOwnAppID)
		{
			return Native.SteamAPI_RestartAppIfNecessary(unOwnAppID);
		}
	}
	internal static class SteamGameServer
	{
		internal static class Native
		{
			[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl)]
			public static extern void SteamGameServer_RunCallbacks();

			[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl)]
			public static extern void SteamGameServer_Shutdown();

			[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl)]
			public static extern HSteamPipe SteamGameServer_GetHSteamPipe();
		}

		internal static void RunCallbacks()
		{
			Native.SteamGameServer_RunCallbacks();
		}

		internal static void Shutdown()
		{
			Native.SteamGameServer_Shutdown();
		}

		internal static HSteamPipe GetHSteamPipe()
		{
			return Native.SteamGameServer_GetHSteamPipe();
		}
	}
	internal static class SteamInternal
	{
		internal static class Native
		{
			[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl)]
			[return: MarshalAs(UnmanagedType.I1)]
			public static extern bool SteamInternal_GameServer_Init(uint unIP, ushort usPort, ushort usGamePort, ushort usQueryPort, int eServerMode, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersionString);
		}

		internal static bool GameServer_Init(uint unIP, ushort usPort, ushort usGamePort, ushort usQueryPort, int eServerMode, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersionString)
		{
			return Native.SteamInternal_GameServer_Init(unIP, usPort, usGamePort, usQueryPort, eServerMode, pchVersionString);
		}
	}
	public enum CallbackType
	{
		SteamServersConnected = 101,
		SteamServerConnectFailure = 102,
		SteamServersDisconnected = 103,
		ClientGameServerDeny = 113,
		GSPolicyResponse = 115,
		IPCFailure = 117,
		LicensesUpdated = 125,
		ValidateAuthTicketResponse = 143,
		MicroTxnAuthorizationResponse = 152,
		EncryptedAppTicketResponse = 154,
		GetAuthSessionTicketResponse = 163,
		GameWebCallback = 164,
		StoreAuthURLResponse = 165,
		MarketEligibilityResponse = 166,
		DurationControl = 167,
		GSClientApprove = 201,
		GSClientDeny = 202,
		GSClientKick = 203,
		GSClientAchievementStatus = 206,
		GSGameplayStats = 207,
		GSClientGroupStatus = 208,
		GSReputation = 209,
		AssociateWithClanResult = 210,
		ComputeNewPlayerCompatibilityResult = 211,
		PersonaStateChange = 304,
		GameOverlayActivated = 331,
		GameServerChangeRequested = 332,
		GameLobbyJoinRequested = 333,
		AvatarImageLoaded = 334,
		ClanOfficerListResponse = 335,
		FriendRichPresenceUpdate = 336,
		GameRichPresenceJoinRequested = 337,
		GameConnectedClanChatMsg = 338,
		GameConnectedChatJoin = 339,
		GameConnectedChatLeave = 340,
		DownloadClanActivityCountsResult = 341,
		JoinClanChatRoomCompletionResult = 342,
		GameConnectedFriendChatMsg = 343,
		FriendsGetFollowerCount = 344,
		FriendsIsFollowing = 345,
		FriendsEnumerateFollowingList = 346,
		SetPersonaNameResponse = 347,
		UnreadChatMessagesChanged = 348,
		FavoritesListChanged = 502,
		LobbyInvite = 503,
		LobbyEnter = 504,
		LobbyDataUpdate = 505,
		LobbyChatUpdate = 506,
		LobbyChatMsg = 507,
		LobbyGameCreated = 509,
		LobbyMatchList = 510,
		LobbyKicked = 512,
		LobbyCreated = 513,
		PSNGameBootInviteResult = 515,
		FavoritesListAccountsUpdated = 516,
		IPCountry = 701,
		LowBatteryPower = 702,
		SteamAPICallCompleted = 703,
		SteamShutdown = 704,
		CheckFileSignature = 705,
		GamepadTextInputDismissed = 714,
		DlcInstalled = 1005,
		RegisterActivationCodeResponse = 1008,
		NewUrlLaunchParameters = 1014,
		AppProofOfPurchaseKeyResponse = 1021,
		FileDetailsResult = 1023,
		UserStatsReceived = 1101,
		UserStatsStored = 1102,
		UserAchievementStored = 1103,
		LeaderboardFindResult = 1104,
		LeaderboardScoresDownloaded = 1105,
		LeaderboardScoreUploaded = 1106,
		NumberOfCurrentPlayers = 1107,
		UserStatsUnloaded = 1108,
		GSStatsUnloaded = 1108,
		UserAchievementIconFetched = 1109,
		GlobalAchievementPercentagesReady = 1110,
		LeaderboardUGCSet = 1111,
		GlobalStatsReceived = 1112,
		P2PSessionRequest = 1202,
		P2PSessionConnectFail = 1203,
		SteamNetConnectionStatusChangedCallback = 1221,
		SteamNetAuthenticationStatus = 1222,
		SteamRelayNetworkStatus = 1281,
		RemoteStorageAppSyncedClient = 1301,
		RemoteStorageAppSyncedServer = 1302,
		RemoteStorageAppSyncProgress = 1303,
		RemoteStorageAppSyncStatusCheck = 1305,
		RemoteStorageFileShareResult = 1307,
		RemoteStoragePublishFileResult = 1309,
		RemoteStorageDeletePublishedFileResult = 1311,
		RemoteStorageEnumerateUserPublishedFilesResult = 1312,
		RemoteStorageSubscribePublishedFileResult = 1313,
		RemoteStorageEnumerateUserSubscribedFilesResult = 1314,
		RemoteStorageUnsubscribePublishedFileResult = 1315,
		RemoteStorageUpdatePublishedFileResult = 1316,
		RemoteStorageDownloadUGCResult = 1317,
		RemoteStorageGetPublishedFileDetailsResult = 1318,
		RemoteStorageEnumerateWorkshopFilesResult = 1319,
		RemoteStorageGetPublishedItemVoteDetailsResult = 1320,
		RemoteStoragePublishedFileSubscribed = 1321,
		RemoteStoragePublishedFileUnsubscribed = 1322,
		RemoteStoragePublishedFileDeleted = 1323,
		RemoteStorageUpdateUserPublishedItemVoteResult = 1324,
		RemoteStorageUserVoteDetails = 1325,
		RemoteStorageEnumerateUserSharedWorkshopFilesResult = 1326,
		RemoteStorageSetUserPublishedFileActionResult = 1327,
		RemoteStorageEnumeratePublishedFilesByUserActionResult = 1328,
		RemoteStoragePublishFileProgress = 1329,
		RemoteStoragePublishedFileUpdated = 1330,
		RemoteStorageFileWriteAsyncComplete = 1331,
		RemoteStorageFileReadAsyncComplete = 1332,
		GSStatsReceived = 1800,
		GSStatsStored = 1801,
		HTTPRequestCompleted = 2101,
		HTTPRequestHeadersReceived = 2102,
		HTTPRequestDataReceived = 2103,
		ScreenshotReady = 2301,
		ScreenshotRequested = 2302,
		SteamUGCQueryCompleted = 3401,
		SteamUGCRequestUGCDetailsResult = 3402,
		CreateItemResult = 3403,
		SubmitItemUpdateResult = 3404,
		ItemInstalled = 3405,
		DownloadItemResult = 3406,
		UserFavoriteItemsListChanged = 3407,
		SetUserItemVoteResult = 3408,
		GetUserItemVoteResult = 3409,
		StartPlaytimeTrackingResult = 3410,
		StopPlaytimeTrackingResult = 3411,
		AddUGCDependencyResult = 3412,
		RemoveUGCDependencyResult = 3413,
		AddAppDependencyResult = 3414,
		RemoveAppDependencyResult = 3415,
		GetAppDependenciesResult = 3416,
		DeleteItemResult = 3417,
		SteamAppInstalled = 3901,
		SteamAppUninstalled = 3902,
		PlaybackStatusHasChanged = 4001,
		VolumeHasChanged = 4002,
		MusicPlayerWantsVolume = 4011,
		MusicPlayerSelectsQueueEntry = 4012,
		MusicPlayerSelectsPlaylistEntry = 4013,
		MusicPlayerRemoteWillActivate = 4101,
		MusicPlayerRemoteWillDeactivate = 4102,
		MusicPlayerRemoteToFront = 4103,
		MusicPlayerWillQuit = 4104,
		MusicPlayerWantsPlay = 4105,
		MusicPlayerWantsPause = 4106,
		MusicPlayerWantsPlayPrevious = 4107,
		MusicPlayerWantsPlayNext = 4108,
		MusicPlayerWantsShuffled = 4109,
		MusicPlayerWantsLooped = 4110,
		MusicPlayerWantsPlayingRepeatStatus = 4114,
		HTML_BrowserReady = 4501,
		HTML_NeedsPaint = 4502,
		HTML_StartRequest = 4503,
		HTML_CloseBrowser = 4504,
		HTML_URLChanged = 4505,
		HTML_FinishedRequest = 4506,
		HTML_OpenLinkInNewTab = 4507,
		HTML_ChangedTitle = 4508,
		HTML_SearchResults = 4509,
		HTML_CanGoBackAndForward = 4510,
		HTML_HorizontalScroll = 4511,
		HTML_VerticalScroll = 4512,
		HTML_LinkAtPosition = 4513,
		HTML_JSAlert = 4514,
		HTML_JSConfirm = 4515,
		HTML_FileOpenDialog = 4516,
		HTML_NewWindow = 4521,
		HTML_SetCursor = 4522,
		HTML_StatusText = 4523,
		HTML_ShowToolTip = 4524,
		HTML_UpdateToolTip = 4525,
		HTML_HideToolTip = 4526,
		HTML_BrowserRestarted = 4527,
		BroadcastUploadStart = 4604,
		BroadcastUploadStop = 4605,
		GetVideoURLResult = 4611,
		GetOPFSettingsResult = 4624,
		SteamInventoryResultReady = 4700,
		SteamInventoryFullUpdate = 4701,
		SteamInventoryDefinitionUpdate = 4702,
		SteamInventoryEligiblePromoItemDefIDs = 4703,
		SteamInventoryStartPurchaseResult = 4704,
		SteamInventoryRequestPricesResult = 4705,
		SteamParentalSettingsChanged = 5001,
		SearchForGameProgressCallback = 5201,
		SearchForGameResultCallback = 5202,
		RequestPlayersForGameProgressCallback = 5211,
		RequestPlayersForGameResultCallback = 5212,
		RequestPlayersForGameFinalResultCallback = 5213,
		SubmitPlayerResultResultCallback = 5214,
		EndGameResultCallback = 5215,
		JoinPartyCallback = 5301,
		CreateBeaconCallback = 5302,
		ReservationNotificationCallback = 5303,
		ChangeNumOpenSlotsCallback = 5304,
		AvailableBeaconLocationsUpdated = 5305,
		ActiveBeaconsUpdated = 5306,
		SteamRemotePlaySessionConnected = 5701,
		SteamRemotePlaySessionDisconnected = 5702
	}
	internal static class CallbackTypeFactory
	{
		internal static Dictionary<CallbackType, Type> All = new Dictionary<CallbackType, Type>
		{
			{
				CallbackType.SteamServersConnected,
				typeof(SteamServersConnected_t)
			},
			{
				CallbackType.SteamServerConnectFailure,
				typeof(SteamServerConnectFailure_t)
			},
			{
				CallbackType.SteamServersDisconnected,
				typeof(SteamServersDisconnected_t)
			},
			{
				CallbackType.ClientGameServerDeny,
				typeof(ClientGameServerDeny_t)
			},
			{
				CallbackType.GSPolicyResponse,
				typeof(GSPolicyResponse_t)
			},
			{
				CallbackType.IPCFailure,
				typeof(IPCFailure_t)
			},
			{
				CallbackType.LicensesUpdated,
				typeof(LicensesUpdated_t)
			},
			{
				CallbackType.ValidateAuthTicketResponse,
				typeof(ValidateAuthTicketResponse_t)
			},
			{
				CallbackType.MicroTxnAuthorizationResponse,
				typeof(MicroTxnAuthorizationResponse_t)
			},
			{
				CallbackType.EncryptedAppTicketResponse,
				typeof(EncryptedAppTicketResponse_t)
			},
			{
				CallbackType.GetAuthSessionTicketResponse,
				typeof(GetAuthSessionTicketResponse_t)
			},
			{
				CallbackType.GameWebCallback,
				typeof(GameWebCallback_t)
			},
			{
				CallbackType.StoreAuthURLResponse,
				typeof(StoreAuthURLResponse_t)
			},
			{
				CallbackType.MarketEligibilityResponse,
				typeof(MarketEligibilityResponse_t)
			},
			{
				CallbackType.DurationControl,
				typeof(DurationControl_t)
			},
			{
				CallbackType.GSClientApprove,
				typeof(GSClientApprove_t)
			},
			{
				CallbackType.GSClientDeny,
				typeof(GSClientDeny_t)
			},
			{
				CallbackType.GSClientKick,
				typeof(GSClientKick_t)
			},
			{
				CallbackType.GSClientAchievementStatus,
				typeof(GSClientAchievementStatus_t)
			},
			{
				CallbackType.GSGameplayStats,
				typeof(GSGameplayStats_t)
			},
			{
				CallbackType.GSClientGroupStatus,
				typeof(GSClientGroupStatus_t)
			},
			{
				CallbackType.GSReputation,
				typeof(GSReputation_t)
			},
			{
				CallbackType.AssociateWithClanResult,
				typeof(AssociateWithClanResult_t)
			},
			{
				CallbackType.ComputeNewPlayerCompatibilityResult,
				typeof(ComputeNewPlayerCompatibilityResult_t)
			},
			{
				CallbackType.PersonaStateChange,
				typeof(PersonaStateChange_t)
			},
			{
				CallbackType.GameOverlayActivated,
				typeof(GameOverlayActivated_t)
			},
			{
				CallbackType.GameServerChangeRequested,
				typeof(GameServerChangeRequested_t)
			},
			{
				CallbackType.GameLobbyJoinRequested,
				typeof(GameLobbyJoinRequested_t)
			},
			{
				CallbackType.AvatarImageLoaded,
				typeof(AvatarImageLoaded_t)
			},
			{
				CallbackType.ClanOfficerListResponse,
				typeof(ClanOfficerListResponse_t)
			},
			{
				CallbackType.FriendRichPresenceUpdate,
				typeof(FriendRichPresenceUpdate_t)
			},
			{
				CallbackType.GameRichPresenceJoinRequested,
				typeof(GameRichPresenceJoinRequested_t)
			},
			{
				CallbackType.GameConnectedClanChatMsg,
				typeof(GameConnectedClanChatMsg_t)
			},
			{
				CallbackType.GameConnectedChatJoin,
				typeof(GameConnectedChatJoin_t)
			},
			{
				CallbackType.GameConnectedChatLeave,
				typeof(GameConnectedChatLeave_t)
			},
			{
				CallbackType.DownloadClanActivityCountsResult,
				typeof(DownloadClanActivityCountsResult_t)
			},
			{
				CallbackType.JoinClanChatRoomCompletionResult,
				typeof(JoinClanChatRoomCompletionResult_t)
			},
			{
				CallbackType.GameConnectedFriendChatMsg,
				typeof(GameConnectedFriendChatMsg_t)
			},
			{
				CallbackType.FriendsGetFollowerCount,
				typeof(FriendsGetFollowerCount_t)
			},
			{
				CallbackType.FriendsIsFollowing,
				typeof(FriendsIsFollowing_t)
			},
			{
				CallbackType.FriendsEnumerateFollowingList,
				typeof(FriendsEnumerateFollowingList_t)
			},
			{
				CallbackType.SetPersonaNameResponse,
				typeof(SetPersonaNameResponse_t)
			},
			{
				CallbackType.UnreadChatMessagesChanged,
				typeof(UnreadChatMessagesChanged_t)
			},
			{
				CallbackType.FavoritesListChanged,
				typeof(FavoritesListChanged_t)
			},
			{
				CallbackType.LobbyInvite,
				typeof(LobbyInvite_t)
			},
			{
				CallbackType.LobbyEnter,
				typeof(LobbyEnter_t)
			},
			{
				CallbackType.LobbyDataUpdate,
				typeof(LobbyDataUpdate_t)
			},
			{
				CallbackType.LobbyChatUpdate,
				typeof(LobbyChatUpdate_t)
			},
			{
				CallbackType.LobbyChatMsg,
				typeof(LobbyChatMsg_t)
			},
			{
				CallbackType.LobbyGameCreated,
				typeof(LobbyGameCreated_t)
			},
			{
				CallbackType.LobbyMatchList,
				typeof(LobbyMatchList_t)
			},
			{
				CallbackType.LobbyKicked,
				typeof(LobbyKicked_t)
			},
			{
				CallbackType.LobbyCreated,
				typeof(LobbyCreated_t)
			},
			{
				CallbackType.PSNGameBootInviteResult,
				typeof(PSNGameBootInviteResult_t)
			},
			{
				CallbackType.FavoritesListAccountsUpdated,
				typeof(FavoritesListAccountsUpdated_t)
			},
			{
				CallbackType.IPCountry,
				typeof(IPCountry_t)
			},
			{
				CallbackType.LowBatteryPower,
				typeof(LowBatteryPower_t)
			},
			{
				CallbackType.SteamAPICallCompleted,
				typeof(SteamAPICallCompleted_t)
			},
			{
				CallbackType.SteamShutdown,
				typeof(SteamShutdown_t)
			},
			{
				CallbackType.CheckFileSignature,
				typeof(CheckFileSignature_t)
			},
			{
				CallbackType.GamepadTextInputDismissed,
				typeof(GamepadTextInputDismissed_t)
			},
			{
				CallbackType.DlcInstalled,
				typeof(DlcInstalled_t)
			},
			{
				CallbackType.RegisterActivationCodeResponse,
				typeof(RegisterActivationCodeResponse_t)
			},
			{
				CallbackType.NewUrlLaunchParameters,
				typeof(NewUrlLaunchParameters_t)
			},
			{
				CallbackType.AppProofOfPurchaseKeyResponse,
				typeof(AppProofOfPurchaseKeyResponse_t)
			},
			{
				CallbackType.FileDetailsResult,
				typeof(FileDetailsResult_t)
			},
			{
				CallbackType.UserStatsReceived,
				typeof(UserStatsReceived_t)
			},
			{
				CallbackType.UserStatsStored,
				typeof(UserStatsStored_t)
			},
			{
				CallbackType.UserAchievementStored,
				typeof(UserAchievementStored_t)
			},
			{
				CallbackType.LeaderboardFindResult,
				typeof(LeaderboardFindResult_t)
			},
			{
				CallbackType.LeaderboardScoresDownloaded,
				typeof(LeaderboardScoresDownloaded_t)
			},
			{
				CallbackType.LeaderboardScoreUploaded,
				typeof(LeaderboardScoreUploaded_t)
			},
			{
				CallbackType.NumberOfCurrentPlayers,
				typeof(NumberOfCurrentPlayers_t)
			},
			{
				CallbackType.UserStatsUnloaded,
				typeof(UserStatsUnloaded_t)
			},
			{
				CallbackType.UserAchievementIconFetched,
				typeof(UserAchievementIconFetched_t)
			},
			{
				CallbackType.GlobalAchievementPercentagesReady,
				typeof(GlobalAchievementPercentagesReady_t)
			},
			{
				CallbackType.LeaderboardUGCSet,
				typeof(LeaderboardUGCSet_t)
			},
			{
				CallbackType.GlobalStatsReceived,
				typeof(GlobalStatsReceived_t)
			},
			{
				CallbackType.P2PSessionRequest,
				typeof(P2PSessionRequest_t)
			},
			{
				CallbackType.P2PSessionConnectFail,
				typeof(P2PSessionConnectFail_t)
			},
			{
				CallbackType.SteamNetConnectionStatusChangedCallback,
				typeof(SteamNetConnectionStatusChangedCallback_t)
			},
			{
				CallbackType.SteamNetAuthenticationStatus,
				typeof(SteamNetAuthenticationStatus_t)
			},
			{
				CallbackType.SteamRelayNetworkStatus,
				typeof(SteamRelayNetworkStatus_t)
			},
			{
				CallbackType.RemoteStorageAppSyncedClient,
				typeof(RemoteStorageAppSyncedClient_t)
			},
			{
				CallbackType.RemoteStorageAppSyncedServer,
				typeof(RemoteStorageAppSyncedServer_t)
			},
			{
				CallbackType.RemoteStorageAppSyncProgress,
				typeof(RemoteStorageAppSyncProgress_t)
			},
			{
				CallbackType.RemoteStorageAppSyncStatusCheck,
				typeof(RemoteStorageAppSyncStatusCheck_t)
			},
			{
				CallbackType.RemoteStorageFileShareResult,
				typeof(RemoteStorageFileShareResult_t)
			},
			{
				CallbackType.RemoteStoragePublishFileResult,
				typeof(RemoteStoragePublishFileResult_t)
			},
			{
				CallbackType.RemoteStorageDeletePublishedFileResult,
				typeof(RemoteStorageDeletePublishedFileResult_t)
			},
			{
				CallbackType.RemoteStorageEnumerateUserPublishedFilesResult,
				typeof(RemoteStorageEnumerateUserPublishedFilesResult_t)
			},
			{
				CallbackType.RemoteStorageSubscribePublishedFileResult,
				typeof(RemoteStorageSubscribePublishedFileResult_t)
			},
			{
				CallbackType.RemoteStorageEnumerateUserSubscribedFilesResult,
				typeof(RemoteStorageEnumerateUserSubscribedFilesResult_t)
			},
			{
				CallbackType.RemoteStorageUnsubscribePublishedFileResult,
				typeof(RemoteStorageUnsubscribePublishedFileResult_t)
			},
			{
				CallbackType.RemoteStorageUpdatePublishedFileResult,
				typeof(RemoteStorageUpdatePublishedFileResult_t)
			},
			{
				CallbackType.RemoteStorageDownloadUGCResult,
				typeof(RemoteStorageDownloadUGCResult_t)
			},
			{
				CallbackType.RemoteStorageGetPublishedFileDetailsResult,
				typeof(RemoteStorageGetPublishedFileDetailsResult_t)
			},
			{
				CallbackType.RemoteStorageEnumerateWorkshopFilesResult,
				typeof(RemoteStorageEnumerateWorkshopFilesResult_t)
			},
			{
				CallbackType.RemoteStorageGetPublishedItemVoteDetailsResult,
				typeof(RemoteStorageGetPublishedItemVoteDetailsResult_t)
			},
			{
				CallbackType.RemoteStoragePublishedFileSubscribed,
				typeof(RemoteStoragePublishedFileSubscribed_t)
			},
			{
				CallbackType.RemoteStoragePublishedFileUnsubscribed,
				typeof(RemoteStoragePublishedFileUnsubscribed_t)
			},
			{
				CallbackType.RemoteStoragePublishedFileDeleted,
				typeof(RemoteStoragePublishedFileDeleted_t)
			},
			{
				CallbackType.RemoteStorageUpdateUserPublishedItemVoteResult,
				typeof(RemoteStorageUpdateUserPublishedItemVoteResult_t)
			},
			{
				CallbackType.RemoteStorageUserVoteDetails,
				typeof(RemoteStorageUserVoteDetails_t)
			},
			{
				CallbackType.RemoteStorageEnumerateUserSharedWorkshopFilesResult,
				typeof(RemoteStorageEnumerateUserSharedWorkshopFilesResult_t)
			},
			{
				CallbackType.RemoteStorageSetUserPublishedFileActionResult,
				typeof(RemoteStorageSetUserPublishedFileActionResult_t)
			},
			{
				CallbackType.RemoteStorageEnumeratePublishedFilesByUserActionResult,
				typeof(RemoteStorageEnumeratePublishedFilesByUserActionResult_t)
			},
			{
				CallbackType.RemoteStoragePublishFileProgress,
				typeof(RemoteStoragePublishFileProgress_t)
			},
			{
				CallbackType.RemoteStoragePublishedFileUpdated,
				typeof(RemoteStoragePublishedFileUpdated_t)
			},
			{
				CallbackType.RemoteStorageFileWriteAsyncComplete,
				typeof(RemoteStorageFileWriteAsyncComplete_t)
			},
			{
				CallbackType.RemoteStorageFileReadAsyncComplete,
				typeof(RemoteStorageFileReadAsyncComplete_t)
			},
			{
				CallbackType.GSStatsReceived,
				typeof(GSStatsReceived_t)
			},
			{
				CallbackType.GSStatsStored,
				typeof(GSStatsStored_t)
			},
			{
				CallbackType.HTTPRequestCompleted,
				typeof(HTTPRequestCompleted_t)
			},
			{
				CallbackType.HTTPRequestHeadersReceived,
				typeof(HTTPRequestHeadersReceived_t)
			},
			{
				CallbackType.HTTPRequestDataReceived,
				typeof(HTTPRequestDataReceived_t)
			},
			{
				CallbackType.ScreenshotReady,
				typeof(ScreenshotReady_t)
			},
			{
				CallbackType.ScreenshotRequested,
				typeof(ScreenshotRequested_t)
			},
			{
				CallbackType.SteamUGCQueryCompleted,
				typeof(SteamUGCQueryCompleted_t)
			},
			{
				CallbackType.SteamUGCRequestUGCDetailsResult,
				typeof(SteamUGCRequestUGCDetailsResult_t)
			},
			{
				CallbackType.CreateItemResult,
				typeof(CreateItemResult_t)
			},
			{
				CallbackType.SubmitItemUpdateResult,
				typeof(SubmitItemUpdateResult_t)
			},
			{
				CallbackType.ItemInstalled,
				typeof(ItemInstalled_t)
			},
			{
				CallbackType.DownloadItemResult,
				typeof(DownloadItemResult_t)
			},
			{
				CallbackType.UserFavoriteItemsListChanged,
				typeof(UserFavoriteItemsListChanged_t)
			},
			{
				CallbackType.SetUserItemVoteResult,
				typeof(SetUserItemVoteResult_t)
			},
			{
				CallbackType.GetUserItemVoteResult,
				typeof(GetUserItemVoteResult_t)
			},
			{
				CallbackType.StartPlaytimeTrackingResult,
				typeof(StartPlaytimeTrackingResult_t)
			},
			{
				CallbackType.StopPlaytimeTrackingResult,
				typeof(StopPlaytimeTrackingResult_t)
			},
			{
				CallbackType.AddUGCDependencyResult,
				typeof(AddUGCDependencyResult_t)
			},
			{
				CallbackType.RemoveUGCDependencyResult,
				typeof(RemoveUGCDependencyResult_t)
			},
			{
				CallbackType.AddAppDependencyResult,
				typeof(AddAppDependencyResult_t)
			},
			{
				CallbackType.RemoveAppDependencyResult,
				typeof(RemoveAppDependencyResult_t)
			},
			{
				CallbackType.GetAppDependenciesResult,
				typeof(GetAppDependenciesResult_t)
			},
			{
				CallbackType.DeleteItemResult,
				typeof(DeleteItemResult_t)
			},
			{
				CallbackType.SteamAppInstalled,
				typeof(SteamAppInstalled_t)
			},
			{
				CallbackType.SteamAppUninstalled,
				typeof(SteamAppUninstalled_t)
			},
			{
				CallbackType.PlaybackStatusHasChanged,
				typeof(PlaybackStatusHasChanged_t)
			},
			{
				CallbackType.VolumeHasChanged,
				typeof(VolumeHasChanged_t)
			},
			{
				CallbackType.MusicPlayerWantsVolume,
				typeof(MusicPlayerWantsVolume_t)
			},
			{
				CallbackType.MusicPlayerSelectsQueueEntry,
				typeof(MusicPlayerSelectsQueueEntry_t)
			},
			{
				CallbackType.MusicPlayerSelectsPlaylistEntry,
				typeof(MusicPlayerSelectsPlaylistEntry_t)
			},
			{
				CallbackType.MusicPlayerRemoteWillActivate,
				typeof(MusicPlayerRemoteWillActivate_t)
			},
			{
				CallbackType.MusicPlayerRemoteWillDeactivate,
				typeof(MusicPlayerRemoteWillDeactivate_t)
			},
			{
				CallbackType.MusicPlayerRemoteToFront,
				typeof(MusicPlayerRemoteToFront_t)
			},
			{
				CallbackType.MusicPlayerWillQuit,
				typeof(MusicPlayerWillQuit_t)
			},
			{
				CallbackType.MusicPlayerWantsPlay,
				typeof(MusicPlayerWantsPlay_t)
			},
			{
				CallbackType.MusicPlayerWantsPause,
				typeof(MusicPlayerWantsPause_t)
			},
			{
				CallbackType.MusicPlayerWantsPlayPrevious,
				typeof(MusicPlayerWantsPlayPrevious_t)
			},
			{
				CallbackType.MusicPlayerWantsPlayNext,
				typeof(MusicPlayerWantsPlayNext_t)
			},
			{
				CallbackType.MusicPlayerWantsShuffled,
				typeof(MusicPlayerWantsShuffled_t)
			},
			{
				CallbackType.MusicPlayerWantsLooped,
				typeof(MusicPlayerWantsLooped_t)
			},
			{
				CallbackType.MusicPlayerWantsPlayingRepeatStatus,
				typeof(MusicPlayerWantsPlayingRepeatStatus_t)
			},
			{
				CallbackType.HTML_BrowserReady,
				typeof(HTML_BrowserReady_t)
			},
			{
				CallbackType.HTML_NeedsPaint,
				typeof(HTML_NeedsPaint_t)
			},
			{
				CallbackType.HTML_StartRequest,
				typeof(HTML_StartRequest_t)
			},
			{
				CallbackType.HTML_CloseBrowser,
				typeof(HTML_CloseBrowser_t)
			},
			{
				CallbackType.HTML_URLChanged,
				typeof(HTML_URLChanged_t)
			},
			{
				CallbackType.HTML_FinishedRequest,
				typeof(HTML_FinishedRequest_t)
			},
			{
				CallbackType.HTML_OpenLinkInNewTab,
				typeof(HTML_OpenLinkInNewTab_t)
			},
			{
				CallbackType.HTML_ChangedTitle,
				typeof(HTML_ChangedTitle_t)
			},
			{
				CallbackType.HTML_SearchResults,
				typeof(HTML_SearchResults_t)
			},
			{
				CallbackType.HTML_CanGoBackAndForward,
				typeof(HTML_CanGoBackAndForward_t)
			},
			{
				CallbackType.HTML_HorizontalScroll,
				typeof(HTML_HorizontalScroll_t)
			},
			{
				CallbackType.HTML_VerticalScroll,
				typeof(HTML_VerticalScroll_t)
			},
			{
				CallbackType.HTML_LinkAtPosition,
				typeof(HTML_LinkAtPosition_t)
			},
			{
				CallbackType.HTML_JSAlert,
				typeof(HTML_JSAlert_t)
			},
			{
				CallbackType.HTML_JSConfirm,
				typeof(HTML_JSConfirm_t)
			},
			{
				CallbackType.HTML_FileOpenDialog,
				typeof(HTML_FileOpenDialog_t)
			},
			{
				CallbackType.HTML_NewWindow,
				typeof(HTML_NewWindow_t)
			},
			{
				CallbackType.HTML_SetCursor,
				typeof(HTML_SetCursor_t)
			},
			{
				CallbackType.HTML_StatusText,
				typeof(HTML_StatusText_t)
			},
			{
				CallbackType.HTML_ShowToolTip,
				typeof(HTML_ShowToolTip_t)
			},
			{
				CallbackType.HTML_UpdateToolTip,
				typeof(HTML_UpdateToolTip_t)
			},
			{
				CallbackType.HTML_HideToolTip,
				typeof(HTML_HideToolTip_t)
			},
			{
				CallbackType.HTML_BrowserRestarted,
				typeof(HTML_BrowserRestarted_t)
			},
			{
				CallbackType.BroadcastUploadStart,
				typeof(BroadcastUploadStart_t)
			},
			{
				CallbackType.BroadcastUploadStop,
				typeof(BroadcastUploadStop_t)
			},
			{
				CallbackType.GetVideoURLResult,
				typeof(GetVideoURLResult_t)
			},
			{
				CallbackType.GetOPFSettingsResult,
				typeof(GetOPFSettingsResult_t)
			},
			{
				CallbackType.SteamInventoryResultReady,
				typeof(SteamInventoryResultReady_t)
			},
			{
				CallbackType.SteamInventoryFullUpdate,
				typeof(SteamInventoryFullUpdate_t)
			},
			{
				CallbackType.SteamInventoryDefinitionUpdate,
				typeof(SteamInventoryDefinitionUpdate_t)
			},
			{
				CallbackType.SteamInventoryEligiblePromoItemDefIDs,
				typeof(SteamInventoryEligiblePromoItemDefIDs_t)
			},
			{
				CallbackType.SteamInventoryStartPurchaseResult,
				typeof(SteamInventoryStartPurchaseResult_t)
			},
			{
				CallbackType.SteamInventoryRequestPricesResult,
				typeof(SteamInventoryRequestPricesResult_t)
			},
			{
				CallbackType.SteamParentalSettingsChanged,
				typeof(SteamParentalSettingsChanged_t)
			},
			{
				CallbackType.SearchForGameProgressCallback,
				typeof(SearchForGameProgressCallback_t)
			},
			{
				CallbackType.SearchForGameResultCallback,
				typeof(SearchForGameResultCallback_t)
			},
			{
				CallbackType.RequestPlayersForGameProgressCallback,
				typeof(RequestPlayersForGameProgressCallback_t)
			},
			{
				CallbackType.RequestPlayersForGameResultCallback,
				typeof(RequestPlayersForGameResultCallback_t)
			},
			{
				CallbackType.RequestPlayersForGameFinalResultCallback,
				typeof(RequestPlayersForGameFinalResultCallback_t)
			},
			{
				CallbackType.SubmitPlayerResultResultCallback,
				typeof(SubmitPlayerResultResultCallback_t)
			},
			{
				CallbackType.EndGameResultCallback,
				typeof(EndGameResultCallback_t)
			},
			{
				CallbackType.JoinPartyCallback,
				typeof(JoinPartyCallback_t)
			},
			{
				CallbackType.CreateBeaconCallback,
				typeof(CreateBeaconCallback_t)
			},
			{
				CallbackType.ReservationNotificationCallback,
				typeof(ReservationNotificationCallback_t)
			},
			{
				CallbackType.ChangeNumOpenSlotsCallback,
				typeof(ChangeNumOpenSlotsCallback_t)
			},
			{
				CallbackType.AvailableBeaconLocationsUpdated,
				typeof(AvailableBeaconLocationsUpdated_t)
			},
			{
				CallbackType.ActiveBeaconsUpdated,
				typeof(ActiveBeaconsUpdated_t)
			},
			{
				CallbackType.SteamRemotePlaySessionConnected,
				typeof(SteamRemotePlaySessionConnected_t)
			},
			{
				CallbackType.SteamRemotePlaySessionDisconnected,
				typeof(SteamRemotePlaySessionDisconnected_t)
			}
		};
	}
	internal class ISteamAppList : SteamInterface
	{
		internal ISteamAppList(bool IsGameServer)
		{
			SetupInterface(IsGameServer);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl)]
		internal static extern IntPtr SteamAPI_SteamAppList_v001();

		public override IntPtr GetUserInterfacePointer()
		{
			return SteamAPI_SteamAppList_v001();
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamAppList_GetNumInstalledApps")]
		private static extern uint _GetNumInstalledApps(IntPtr self);

		internal uint GetNumInstalledApps()
		{
			return _GetNumInstalledApps(Self);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamAppList_GetInstalledApps")]
		private static extern uint _GetInstalledApps(IntPtr self, [In][Out] AppId[] pvecAppID, uint unMaxAppIDs);

		internal uint GetInstalledApps([In][Out] AppId[] pvecAppID, uint unMaxAppIDs)
		{
			return _GetInstalledApps(Self, pvecAppID, unMaxAppIDs);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamAppList_GetAppName")]
		private static extern int _GetAppName(IntPtr self, AppId nAppID, IntPtr pchName, int cchNameMax);

		internal int GetAppName(AppId nAppID, out string pchName)
		{
			IntPtr intPtr = Helpers.TakeMemory();
			int result = _GetAppName(Self, nAppID, intPtr, 32768);
			pchName = Helpers.MemoryToString(intPtr);
			return result;
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamAppList_GetAppInstallDir")]
		private static extern int _GetAppInstallDir(IntPtr self, AppId nAppID, IntPtr pchDirectory, int cchNameMax);

		internal int GetAppInstallDir(AppId nAppID, out string pchDirectory)
		{
			IntPtr intPtr = Helpers.TakeMemory();
			int result = _GetAppInstallDir(Self, nAppID, intPtr, 32768);
			pchDirectory = Helpers.MemoryToString(intPtr);
			return result;
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamAppList_GetAppBuildId")]
		private static extern int _GetAppBuildId(IntPtr self, AppId nAppID);

		internal int GetAppBuildId(AppId nAppID)
		{
			return _GetAppBuildId(Self, nAppID);
		}
	}
	internal class ISteamApps : SteamInterface
	{
		internal ISteamApps(bool IsGameServer)
		{
			SetupInterface(IsGameServer);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl)]
		internal static extern IntPtr SteamAPI_SteamApps_v008();

		public override IntPtr GetUserInterfacePointer()
		{
			return SteamAPI_SteamApps_v008();
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl)]
		internal static extern IntPtr SteamAPI_SteamGameServerApps_v008();

		public override IntPtr GetServerInterfacePointer()
		{
			return SteamAPI_SteamGameServerApps_v008();
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_BIsSubscribed")]
		[return: MarshalAs(UnmanagedType.I1)]
		private static extern bool _BIsSubscribed(IntPtr self);

		internal bool BIsSubscribed()
		{
			return _BIsSubscribed(Self);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_BIsLowViolence")]
		[return: MarshalAs(UnmanagedType.I1)]
		private static extern bool _BIsLowViolence(IntPtr self);

		internal bool BIsLowViolence()
		{
			return _BIsLowViolence(Self);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_BIsCybercafe")]
		[return: MarshalAs(UnmanagedType.I1)]
		private static extern bool _BIsCybercafe(IntPtr self);

		internal bool BIsCybercafe()
		{
			return _BIsCybercafe(Self);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_BIsVACBanned")]
		[return: MarshalAs(UnmanagedType.I1)]
		private static extern bool _BIsVACBanned(IntPtr self);

		internal bool BIsVACBanned()
		{
			return _BIsVACBanned(Self);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_GetCurrentGameLanguage")]
		private static extern Utf8StringPointer _GetCurrentGameLanguage(IntPtr self);

		internal string GetCurrentGameLanguage()
		{
			Utf8StringPointer utf8StringPointer = _GetCurrentGameLanguage(Self);
			return utf8StringPointer;
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_GetAvailableGameLanguages")]
		private static extern Utf8StringPointer _GetAvailableGameLanguages(IntPtr self);

		internal string GetAvailableGameLanguages()
		{
			Utf8StringPointer utf8StringPointer = _GetAvailableGameLanguages(Self);
			return utf8StringPointer;
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_BIsSubscribedApp")]
		[return: MarshalAs(UnmanagedType.I1)]
		private static extern bool _BIsSubscribedApp(IntPtr self, AppId appID);

		internal bool BIsSubscribedApp(AppId appID)
		{
			return _BIsSubscribedApp(Self, appID);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_BIsDlcInstalled")]
		[return: MarshalAs(UnmanagedType.I1)]
		private static extern bool _BIsDlcInstalled(IntPtr self, AppId appID);

		internal bool BIsDlcInstalled(AppId appID)
		{
			return _BIsDlcInstalled(Self, appID);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_GetEarliestPurchaseUnixTime")]
		private static extern uint _GetEarliestPurchaseUnixTime(IntPtr self, AppId nAppID);

		internal uint GetEarliestPurchaseUnixTime(AppId nAppID)
		{
			return _GetEarliestPurchaseUnixTime(Self, nAppID);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_BIsSubscribedFromFreeWeekend")]
		[return: MarshalAs(UnmanagedType.I1)]
		private static extern bool _BIsSubscribedFromFreeWeekend(IntPtr self);

		internal bool BIsSubscribedFromFreeWeekend()
		{
			return _BIsSubscribedFromFreeWeekend(Self);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_GetDLCCount")]
		private static extern int _GetDLCCount(IntPtr self);

		internal int GetDLCCount()
		{
			return _GetDLCCount(Self);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_BGetDLCDataByIndex")]
		[return: MarshalAs(UnmanagedType.I1)]
		private static extern bool _BGetDLCDataByIndex(IntPtr self, int iDLC, ref AppId pAppID, [MarshalAs(UnmanagedType.U1)] ref bool pbAvailable, IntPtr pchName, int cchNameBufferSize);

		internal bool BGetDLCDataByIndex(int iDLC, ref AppId pAppID, [MarshalAs(UnmanagedType.U1)] ref bool pbAvailable, out string pchName)
		{
			IntPtr intPtr = Helpers.TakeMemory();
			bool result = _BGetDLCDataByIndex(Self, iDLC, ref pAppID, ref pbAvailable, intPtr, 32768);
			pchName = Helpers.MemoryToString(intPtr);
			return result;
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_InstallDLC")]
		private static extern void _InstallDLC(IntPtr self, AppId nAppID);

		internal void InstallDLC(AppId nAppID)
		{
			_InstallDLC(Self, nAppID);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_UninstallDLC")]
		private static extern void _UninstallDLC(IntPtr self, AppId nAppID);

		internal void UninstallDLC(AppId nAppID)
		{
			_UninstallDLC(Self, nAppID);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_RequestAppProofOfPurchaseKey")]
		private static extern void _RequestAppProofOfPurchaseKey(IntPtr self, AppId nAppID);

		internal void RequestAppProofOfPurchaseKey(AppId nAppID)
		{
			_RequestAppProofOfPurchaseKey(Self, nAppID);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_GetCurrentBetaName")]
		[return: MarshalAs(UnmanagedType.I1)]
		private static extern bool _GetCurrentBetaName(IntPtr self, IntPtr pchName, int cchNameBufferSize);

		internal bool GetCurrentBetaName(out string pchName)
		{
			IntPtr intPtr = Helpers.TakeMemory();
			bool result = _GetCurrentBetaName(Self, intPtr, 32768);
			pchName = Helpers.MemoryToString(intPtr);
			return result;
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_MarkContentCorrupt")]
		[return: MarshalAs(UnmanagedType.I1)]
		private static extern bool _MarkContentCorrupt(IntPtr self, [MarshalAs(UnmanagedType.U1)] bool bMissingFilesOnly);

		internal bool MarkContentCorrupt([MarshalAs(UnmanagedType.U1)] bool bMissingFilesOnly)
		{
			return _MarkContentCorrupt(Self, bMissingFilesOnly);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_GetInstalledDepots")]
		private static extern uint _GetInstalledDepots(IntPtr self, AppId appID, [In][Out] DepotId_t[] pvecDepots, uint cMaxDepots);

		internal uint GetInstalledDepots(AppId appID, [In][Out] DepotId_t[] pvecDepots, uint cMaxDepots)
		{
			return _GetInstalledDepots(Self, appID, pvecDepots, cMaxDepots);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_GetAppInstallDir")]
		private static extern uint _GetAppInstallDir(IntPtr self, AppId appID, IntPtr pchFolder, uint cchFolderBufferSize);

		internal uint GetAppInstallDir(AppId appID, out string pchFolder)
		{
			IntPtr intPtr = Helpers.TakeMemory();
			uint result = _GetAppInstallDir(Self, appID, intPtr, 32768u);
			pchFolder = Helpers.MemoryToString(intPtr);
			return result;
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_BIsAppInstalled")]
		[return: MarshalAs(UnmanagedType.I1)]
		private static extern bool _BIsAppInstalled(IntPtr self, AppId appID);

		internal bool BIsAppInstalled(AppId appID)
		{
			return _BIsAppInstalled(Self, appID);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_GetAppOwner")]
		private static extern SteamId _GetAppOwner(IntPtr self);

		internal SteamId GetAppOwner()
		{
			return _GetAppOwner(Self);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_GetLaunchQueryParam")]
		private static extern Utf8StringPointer _GetLaunchQueryParam(IntPtr self, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchKey);

		internal string GetLaunchQueryParam([MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchKey)
		{
			Utf8StringPointer utf8StringPointer = _GetLaunchQueryParam(Self, pchKey);
			return utf8StringPointer;
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_GetDlcDownloadProgress")]
		[return: MarshalAs(UnmanagedType.I1)]
		private static extern bool _GetDlcDownloadProgress(IntPtr self, AppId nAppID, ref ulong punBytesDownloaded, ref ulong punBytesTotal);

		internal bool GetDlcDownloadProgress(AppId nAppID, ref ulong punBytesDownloaded, ref ulong punBytesTotal)
		{
			return _GetDlcDownloadProgress(Self, nAppID, ref punBytesDownloaded, ref punBytesTotal);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_GetAppBuildId")]
		private static extern int _GetAppBuildId(IntPtr self);

		internal int GetAppBuildId()
		{
			return _GetAppBuildId(Self);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_RequestAllProofOfPurchaseKeys")]
		private static extern void _RequestAllProofOfPurchaseKeys(IntPtr self);

		internal void RequestAllProofOfPurchaseKeys()
		{
			_RequestAllProofOfPurchaseKeys(Self);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_GetFileDetails")]
		private static extern SteamAPICall_t _GetFileDetails(IntPtr self, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pszFileName);

		internal CallResult<FileDetailsResult_t> GetFileDetails([MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pszFileName)
		{
			SteamAPICall_t call = _GetFileDetails(Self, pszFileName);
			return new CallResult<FileDetailsResult_t>(call, base.IsServer);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_GetLaunchCommandLine")]
		private static extern int _GetLaunchCommandLine(IntPtr self, IntPtr pszCommandLine, int cubCommandLine);

		internal int GetLaunchCommandLine(out string pszCommandLine)
		{
			IntPtr intPtr = Helpers.TakeMemory();
			int result = _GetLaunchCommandLine(Self, intPtr, 32768);
			pszCommandLine = Helpers.MemoryToString(intPtr);
			return result;
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamApps_BIsSubscribedFromFamilySharing")]
		[return: MarshalAs(UnmanagedType.I1)]
		private static extern bool _BIsSubscribedFromFamilySharing(IntPtr self);

		internal bool BIsSubscribedFromFamilySharing()
		{
			return _BIsSubscribedFromFamilySharing(Self);
		}
	}
	internal class ISteamClient : SteamInterface
	{
		internal ISteamClient(bool IsGameServer)
		{
			SetupInterface(IsGameServer);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_CreateSteamPipe")]
		private static extern HSteamPipe _CreateSteamPipe(IntPtr self);

		internal HSteamPipe CreateSteamPipe()
		{
			return _CreateSteamPipe(Self);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_BReleaseSteamPipe")]
		[return: MarshalAs(UnmanagedType.I1)]
		private static extern bool _BReleaseSteamPipe(IntPtr self, HSteamPipe hSteamPipe);

		internal bool BReleaseSteamPipe(HSteamPipe hSteamPipe)
		{
			return _BReleaseSteamPipe(Self, hSteamPipe);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_ConnectToGlobalUser")]
		private static extern HSteamUser _ConnectToGlobalUser(IntPtr self, HSteamPipe hSteamPipe);

		internal HSteamUser ConnectToGlobalUser(HSteamPipe hSteamPipe)
		{
			return _ConnectToGlobalUser(Self, hSteamPipe);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_CreateLocalUser")]
		private static extern HSteamUser _CreateLocalUser(IntPtr self, ref HSteamPipe phSteamPipe, AccountType eAccountType);

		internal HSteamUser CreateLocalUser(ref HSteamPipe phSteamPipe, AccountType eAccountType)
		{
			return _CreateLocalUser(Self, ref phSteamPipe, eAccountType);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_ReleaseUser")]
		private static extern void _ReleaseUser(IntPtr self, HSteamPipe hSteamPipe, HSteamUser hUser);

		internal void ReleaseUser(HSteamPipe hSteamPipe, HSteamUser hUser)
		{
			_ReleaseUser(Self, hSteamPipe, hUser);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetISteamUser")]
		private static extern IntPtr _GetISteamUser(IntPtr self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion);

		internal IntPtr GetISteamUser(HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion)
		{
			return _GetISteamUser(Self, hSteamUser, hSteamPipe, pchVersion);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetISteamGameServer")]
		private static extern IntPtr _GetISteamGameServer(IntPtr self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion);

		internal IntPtr GetISteamGameServer(HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion)
		{
			return _GetISteamGameServer(Self, hSteamUser, hSteamPipe, pchVersion);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_SetLocalIPBinding")]
		private static extern void _SetLocalIPBinding(IntPtr self, ref SteamIPAddress unIP, ushort usPort);

		internal void SetLocalIPBinding(ref SteamIPAddress unIP, ushort usPort)
		{
			_SetLocalIPBinding(Self, ref unIP, usPort);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetISteamFriends")]
		private static extern IntPtr _GetISteamFriends(IntPtr self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion);

		internal IntPtr GetISteamFriends(HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion)
		{
			return _GetISteamFriends(Self, hSteamUser, hSteamPipe, pchVersion);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetISteamUtils")]
		private static extern IntPtr _GetISteamUtils(IntPtr self, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion);

		internal IntPtr GetISteamUtils(HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion)
		{
			return _GetISteamUtils(Self, hSteamPipe, pchVersion);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetISteamMatchmaking")]
		private static extern IntPtr _GetISteamMatchmaking(IntPtr self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion);

		internal IntPtr GetISteamMatchmaking(HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion)
		{
			return _GetISteamMatchmaking(Self, hSteamUser, hSteamPipe, pchVersion);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetISteamMatchmakingServers")]
		private static extern IntPtr _GetISteamMatchmakingServers(IntPtr self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion);

		internal IntPtr GetISteamMatchmakingServers(HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion)
		{
			return _GetISteamMatchmakingServers(Self, hSteamUser, hSteamPipe, pchVersion);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetISteamGenericInterface")]
		private static extern IntPtr _GetISteamGenericInterface(IntPtr self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion);

		internal IntPtr GetISteamGenericInterface(HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion)
		{
			return _GetISteamGenericInterface(Self, hSteamUser, hSteamPipe, pchVersion);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetISteamUserStats")]
		private static extern IntPtr _GetISteamUserStats(IntPtr self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion);

		internal IntPtr GetISteamUserStats(HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion)
		{
			return _GetISteamUserStats(Self, hSteamUser, hSteamPipe, pchVersion);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetISteamGameServerStats")]
		private static extern IntPtr _GetISteamGameServerStats(IntPtr self, HSteamUser hSteamuser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion);

		internal IntPtr GetISteamGameServerStats(HSteamUser hSteamuser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion)
		{
			return _GetISteamGameServerStats(Self, hSteamuser, hSteamPipe, pchVersion);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetISteamApps")]
		private static extern IntPtr _GetISteamApps(IntPtr self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion);

		internal IntPtr GetISteamApps(HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion)
		{
			return _GetISteamApps(Self, hSteamUser, hSteamPipe, pchVersion);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetISteamNetworking")]
		private static extern IntPtr _GetISteamNetworking(IntPtr self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion);

		internal IntPtr GetISteamNetworking(HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion)
		{
			return _GetISteamNetworking(Self, hSteamUser, hSteamPipe, pchVersion);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetISteamRemoteStorage")]
		private static extern IntPtr _GetISteamRemoteStorage(IntPtr self, HSteamUser hSteamuser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion);

		internal IntPtr GetISteamRemoteStorage(HSteamUser hSteamuser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion)
		{
			return _GetISteamRemoteStorage(Self, hSteamuser, hSteamPipe, pchVersion);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetISteamScreenshots")]
		private static extern IntPtr _GetISteamScreenshots(IntPtr self, HSteamUser hSteamuser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion);

		internal IntPtr GetISteamScreenshots(HSteamUser hSteamuser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion)
		{
			return _GetISteamScreenshots(Self, hSteamuser, hSteamPipe, pchVersion);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetISteamGameSearch")]
		private static extern IntPtr _GetISteamGameSearch(IntPtr self, HSteamUser hSteamuser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion);

		internal IntPtr GetISteamGameSearch(HSteamUser hSteamuser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion)
		{
			return _GetISteamGameSearch(Self, hSteamuser, hSteamPipe, pchVersion);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetIPCCallCount")]
		private static extern uint _GetIPCCallCount(IntPtr self);

		internal uint GetIPCCallCount()
		{
			return _GetIPCCallCount(Self);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_SetWarningMessageHook")]
		private static extern void _SetWarningMessageHook(IntPtr self, IntPtr pFunction);

		internal void SetWarningMessageHook(IntPtr pFunction)
		{
			_SetWarningMessageHook(Self, pFunction);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_BShutdownIfAllPipesClosed")]
		[return: MarshalAs(UnmanagedType.I1)]
		private static extern bool _BShutdownIfAllPipesClosed(IntPtr self);

		internal bool BShutdownIfAllPipesClosed()
		{
			return _BShutdownIfAllPipesClosed(Self);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetISteamHTTP")]
		private static extern IntPtr _GetISteamHTTP(IntPtr self, HSteamUser hSteamuser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion);

		internal IntPtr GetISteamHTTP(HSteamUser hSteamuser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion)
		{
			return _GetISteamHTTP(Self, hSteamuser, hSteamPipe, pchVersion);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetISteamController")]
		private static extern IntPtr _GetISteamController(IntPtr self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion);

		internal IntPtr GetISteamController(HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion)
		{
			return _GetISteamController(Self, hSteamUser, hSteamPipe, pchVersion);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetISteamUGC")]
		private static extern IntPtr _GetISteamUGC(IntPtr self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion);

		internal IntPtr GetISteamUGC(HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion)
		{
			return _GetISteamUGC(Self, hSteamUser, hSteamPipe, pchVersion);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetISteamAppList")]
		private static extern IntPtr _GetISteamAppList(IntPtr self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion);

		internal IntPtr GetISteamAppList(HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion)
		{
			return _GetISteamAppList(Self, hSteamUser, hSteamPipe, pchVersion);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetISteamMusic")]
		private static extern IntPtr _GetISteamMusic(IntPtr self, HSteamUser hSteamuser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion);

		internal IntPtr GetISteamMusic(HSteamUser hSteamuser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion)
		{
			return _GetISteamMusic(Self, hSteamuser, hSteamPipe, pchVersion);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetISteamMusicRemote")]
		private static extern IntPtr _GetISteamMusicRemote(IntPtr self, HSteamUser hSteamuser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion);

		internal IntPtr GetISteamMusicRemote(HSteamUser hSteamuser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion)
		{
			return _GetISteamMusicRemote(Self, hSteamuser, hSteamPipe, pchVersion);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetISteamHTMLSurface")]
		private static extern IntPtr _GetISteamHTMLSurface(IntPtr self, HSteamUser hSteamuser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion);

		internal IntPtr GetISteamHTMLSurface(HSteamUser hSteamuser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion)
		{
			return _GetISteamHTMLSurface(Self, hSteamuser, hSteamPipe, pchVersion);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetISteamInventory")]
		private static extern IntPtr _GetISteamInventory(IntPtr self, HSteamUser hSteamuser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion);

		internal IntPtr GetISteamInventory(HSteamUser hSteamuser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion)
		{
			return _GetISteamInventory(Self, hSteamuser, hSteamPipe, pchVersion);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetISteamVideo")]
		private static extern IntPtr _GetISteamVideo(IntPtr self, HSteamUser hSteamuser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion);

		internal IntPtr GetISteamVideo(HSteamUser hSteamuser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion)
		{
			return _GetISteamVideo(Self, hSteamuser, hSteamPipe, pchVersion);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetISteamParentalSettings")]
		private static extern IntPtr _GetISteamParentalSettings(IntPtr self, HSteamUser hSteamuser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion);

		internal IntPtr GetISteamParentalSettings(HSteamUser hSteamuser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion)
		{
			return _GetISteamParentalSettings(Self, hSteamuser, hSteamPipe, pchVersion);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetISteamInput")]
		private static extern IntPtr _GetISteamInput(IntPtr self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion);

		internal IntPtr GetISteamInput(HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion)
		{
			return _GetISteamInput(Self, hSteamUser, hSteamPipe, pchVersion);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetISteamParties")]
		private static extern IntPtr _GetISteamParties(IntPtr self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion);

		internal IntPtr GetISteamParties(HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion)
		{
			return _GetISteamParties(Self, hSteamUser, hSteamPipe, pchVersion);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamClient_GetISteamRemotePlay")]
		private static extern IntPtr _GetISteamRemotePlay(IntPtr self, HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion);

		internal IntPtr GetISteamRemotePlay(HSteamUser hSteamUser, HSteamPipe hSteamPipe, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchVersion)
		{
			return _GetISteamRemotePlay(Self, hSteamUser, hSteamPipe, pchVersion);
		}
	}
	internal class ISteamController : SteamInterface
	{
		internal ISteamController(bool IsGameServer)
		{
			SetupInterface(IsGameServer);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl)]
		internal static extern IntPtr SteamAPI_SteamController_v007();

		public override IntPtr GetUserInterfacePointer()
		{
			return SteamAPI_SteamController_v007();
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_Init")]
		[return: MarshalAs(UnmanagedType.I1)]
		private static extern bool _Init(IntPtr self);

		internal bool Init()
		{
			return _Init(Self);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_Shutdown")]
		[return: MarshalAs(UnmanagedType.I1)]
		private static extern bool _Shutdown(IntPtr self);

		internal bool Shutdown()
		{
			return _Shutdown(Self);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_RunFrame")]
		private static extern void _RunFrame(IntPtr self);

		internal void RunFrame()
		{
			_RunFrame(Self);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_GetConnectedControllers")]
		private static extern int _GetConnectedControllers(IntPtr self, [In][Out] ControllerHandle_t[] handlesOut);

		internal int GetConnectedControllers([In][Out] ControllerHandle_t[] handlesOut)
		{
			return _GetConnectedControllers(Self, handlesOut);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_GetActionSetHandle")]
		private static extern ControllerActionSetHandle_t _GetActionSetHandle(IntPtr self, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pszActionSetName);

		internal ControllerActionSetHandle_t GetActionSetHandle([MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pszActionSetName)
		{
			return _GetActionSetHandle(Self, pszActionSetName);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_ActivateActionSet")]
		private static extern void _ActivateActionSet(IntPtr self, ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle);

		internal void ActivateActionSet(ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle)
		{
			_ActivateActionSet(Self, controllerHandle, actionSetHandle);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_GetCurrentActionSet")]
		private static extern ControllerActionSetHandle_t _GetCurrentActionSet(IntPtr self, ControllerHandle_t controllerHandle);

		internal ControllerActionSetHandle_t GetCurrentActionSet(ControllerHandle_t controllerHandle)
		{
			return _GetCurrentActionSet(Self, controllerHandle);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_ActivateActionSetLayer")]
		private static extern void _ActivateActionSetLayer(IntPtr self, ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetLayerHandle);

		internal void ActivateActionSetLayer(ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetLayerHandle)
		{
			_ActivateActionSetLayer(Self, controllerHandle, actionSetLayerHandle);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_DeactivateActionSetLayer")]
		private static extern void _DeactivateActionSetLayer(IntPtr self, ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetLayerHandle);

		internal void DeactivateActionSetLayer(ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetLayerHandle)
		{
			_DeactivateActionSetLayer(Self, controllerHandle, actionSetLayerHandle);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_DeactivateAllActionSetLayers")]
		private static extern void _DeactivateAllActionSetLayers(IntPtr self, ControllerHandle_t controllerHandle);

		internal void DeactivateAllActionSetLayers(ControllerHandle_t controllerHandle)
		{
			_DeactivateAllActionSetLayers(Self, controllerHandle);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_GetActiveActionSetLayers")]
		private static extern int _GetActiveActionSetLayers(IntPtr self, ControllerHandle_t controllerHandle, [In][Out] ControllerActionSetHandle_t[] handlesOut);

		internal int GetActiveActionSetLayers(ControllerHandle_t controllerHandle, [In][Out] ControllerActionSetHandle_t[] handlesOut)
		{
			return _GetActiveActionSetLayers(Self, controllerHandle, handlesOut);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_GetDigitalActionHandle")]
		private static extern ControllerDigitalActionHandle_t _GetDigitalActionHandle(IntPtr self, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pszActionName);

		internal ControllerDigitalActionHandle_t GetDigitalActionHandle([MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pszActionName)
		{
			return _GetDigitalActionHandle(Self, pszActionName);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_GetDigitalActionData")]
		private static extern DigitalState _GetDigitalActionData(IntPtr self, ControllerHandle_t controllerHandle, ControllerDigitalActionHandle_t digitalActionHandle);

		internal DigitalState GetDigitalActionData(ControllerHandle_t controllerHandle, ControllerDigitalActionHandle_t digitalActionHandle)
		{
			return _GetDigitalActionData(Self, controllerHandle, digitalActionHandle);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_GetDigitalActionOrigins")]
		private static extern int _GetDigitalActionOrigins(IntPtr self, ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle, ControllerDigitalActionHandle_t digitalActionHandle, ref ControllerActionOrigin originsOut);

		internal int GetDigitalActionOrigins(ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle, ControllerDigitalActionHandle_t digitalActionHandle, ref ControllerActionOrigin originsOut)
		{
			return _GetDigitalActionOrigins(Self, controllerHandle, actionSetHandle, digitalActionHandle, ref originsOut);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_GetAnalogActionHandle")]
		private static extern ControllerAnalogActionHandle_t _GetAnalogActionHandle(IntPtr self, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pszActionName);

		internal ControllerAnalogActionHandle_t GetAnalogActionHandle([MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pszActionName)
		{
			return _GetAnalogActionHandle(Self, pszActionName);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_GetAnalogActionData")]
		private static extern AnalogState _GetAnalogActionData(IntPtr self, ControllerHandle_t controllerHandle, ControllerAnalogActionHandle_t analogActionHandle);

		internal AnalogState GetAnalogActionData(ControllerHandle_t controllerHandle, ControllerAnalogActionHandle_t analogActionHandle)
		{
			return _GetAnalogActionData(Self, controllerHandle, analogActionHandle);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_GetAnalogActionOrigins")]
		private static extern int _GetAnalogActionOrigins(IntPtr self, ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle, ControllerAnalogActionHandle_t analogActionHandle, ref ControllerActionOrigin originsOut);

		internal int GetAnalogActionOrigins(ControllerHandle_t controllerHandle, ControllerActionSetHandle_t actionSetHandle, ControllerAnalogActionHandle_t analogActionHandle, ref ControllerActionOrigin originsOut)
		{
			return _GetAnalogActionOrigins(Self, controllerHandle, actionSetHandle, analogActionHandle, ref originsOut);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_GetGlyphForActionOrigin")]
		private static extern Utf8StringPointer _GetGlyphForActionOrigin(IntPtr self, ControllerActionOrigin eOrigin);

		internal string GetGlyphForActionOrigin(ControllerActionOrigin eOrigin)
		{
			Utf8StringPointer utf8StringPointer = _GetGlyphForActionOrigin(Self, eOrigin);
			return utf8StringPointer;
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_GetStringForActionOrigin")]
		private static extern Utf8StringPointer _GetStringForActionOrigin(IntPtr self, ControllerActionOrigin eOrigin);

		internal string GetStringForActionOrigin(ControllerActionOrigin eOrigin)
		{
			Utf8StringPointer utf8StringPointer = _GetStringForActionOrigin(Self, eOrigin);
			return utf8StringPointer;
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_StopAnalogActionMomentum")]
		private static extern void _StopAnalogActionMomentum(IntPtr self, ControllerHandle_t controllerHandle, ControllerAnalogActionHandle_t eAction);

		internal void StopAnalogActionMomentum(ControllerHandle_t controllerHandle, ControllerAnalogActionHandle_t eAction)
		{
			_StopAnalogActionMomentum(Self, controllerHandle, eAction);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_GetMotionData")]
		private static extern MotionState _GetMotionData(IntPtr self, ControllerHandle_t controllerHandle);

		internal MotionState GetMotionData(ControllerHandle_t controllerHandle)
		{
			return _GetMotionData(Self, controllerHandle);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_TriggerHapticPulse")]
		private static extern void _TriggerHapticPulse(IntPtr self, ControllerHandle_t controllerHandle, SteamControllerPad eTargetPad, ushort usDurationMicroSec);

		internal void TriggerHapticPulse(ControllerHandle_t controllerHandle, SteamControllerPad eTargetPad, ushort usDurationMicroSec)
		{
			_TriggerHapticPulse(Self, controllerHandle, eTargetPad, usDurationMicroSec);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_TriggerRepeatedHapticPulse")]
		private static extern void _TriggerRepeatedHapticPulse(IntPtr self, ControllerHandle_t controllerHandle, SteamControllerPad eTargetPad, ushort usDurationMicroSec, ushort usOffMicroSec, ushort unRepeat, uint nFlags);

		internal void TriggerRepeatedHapticPulse(ControllerHandle_t controllerHandle, SteamControllerPad eTargetPad, ushort usDurationMicroSec, ushort usOffMicroSec, ushort unRepeat, uint nFlags)
		{
			_TriggerRepeatedHapticPulse(Self, controllerHandle, eTargetPad, usDurationMicroSec, usOffMicroSec, unRepeat, nFlags);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_TriggerVibration")]
		private static extern void _TriggerVibration(IntPtr self, ControllerHandle_t controllerHandle, ushort usLeftSpeed, ushort usRightSpeed);

		internal void TriggerVibration(ControllerHandle_t controllerHandle, ushort usLeftSpeed, ushort usRightSpeed)
		{
			_TriggerVibration(Self, controllerHandle, usLeftSpeed, usRightSpeed);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_SetLEDColor")]
		private static extern void _SetLEDColor(IntPtr self, ControllerHandle_t controllerHandle, byte nColorR, byte nColorG, byte nColorB, uint nFlags);

		internal void SetLEDColor(ControllerHandle_t controllerHandle, byte nColorR, byte nColorG, byte nColorB, uint nFlags)
		{
			_SetLEDColor(Self, controllerHandle, nColorR, nColorG, nColorB, nFlags);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_ShowBindingPanel")]
		[return: MarshalAs(UnmanagedType.I1)]
		private static extern bool _ShowBindingPanel(IntPtr self, ControllerHandle_t controllerHandle);

		internal bool ShowBindingPanel(ControllerHandle_t controllerHandle)
		{
			return _ShowBindingPanel(Self, controllerHandle);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_GetInputTypeForHandle")]
		private static extern InputType _GetInputTypeForHandle(IntPtr self, ControllerHandle_t controllerHandle);

		internal InputType GetInputTypeForHandle(ControllerHandle_t controllerHandle)
		{
			return _GetInputTypeForHandle(Self, controllerHandle);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_GetControllerForGamepadIndex")]
		private static extern ControllerHandle_t _GetControllerForGamepadIndex(IntPtr self, int nIndex);

		internal ControllerHandle_t GetControllerForGamepadIndex(int nIndex)
		{
			return _GetControllerForGamepadIndex(Self, nIndex);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_GetGamepadIndexForController")]
		private static extern int _GetGamepadIndexForController(IntPtr self, ControllerHandle_t ulControllerHandle);

		internal int GetGamepadIndexForController(ControllerHandle_t ulControllerHandle)
		{
			return _GetGamepadIndexForController(Self, ulControllerHandle);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_GetStringForXboxOrigin")]
		private static extern Utf8StringPointer _GetStringForXboxOrigin(IntPtr self, XboxOrigin eOrigin);

		internal string GetStringForXboxOrigin(XboxOrigin eOrigin)
		{
			Utf8StringPointer utf8StringPointer = _GetStringForXboxOrigin(Self, eOrigin);
			return utf8StringPointer;
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_GetGlyphForXboxOrigin")]
		private static extern Utf8StringPointer _GetGlyphForXboxOrigin(IntPtr self, XboxOrigin eOrigin);

		internal string GetGlyphForXboxOrigin(XboxOrigin eOrigin)
		{
			Utf8StringPointer utf8StringPointer = _GetGlyphForXboxOrigin(Self, eOrigin);
			return utf8StringPointer;
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_GetActionOriginFromXboxOrigin")]
		private static extern ControllerActionOrigin _GetActionOriginFromXboxOrigin(IntPtr self, ControllerHandle_t controllerHandle, XboxOrigin eOrigin);

		internal ControllerActionOrigin GetActionOriginFromXboxOrigin(ControllerHandle_t controllerHandle, XboxOrigin eOrigin)
		{
			return _GetActionOriginFromXboxOrigin(Self, controllerHandle, eOrigin);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_TranslateActionOrigin")]
		private static extern ControllerActionOrigin _TranslateActionOrigin(IntPtr self, InputType eDestinationInputType, ControllerActionOrigin eSourceOrigin);

		internal ControllerActionOrigin TranslateActionOrigin(InputType eDestinationInputType, ControllerActionOrigin eSourceOrigin)
		{
			return _TranslateActionOrigin(Self, eDestinationInputType, eSourceOrigin);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamController_GetControllerBindingRevision")]
		[return: MarshalAs(UnmanagedType.I1)]
		private static extern bool _GetControllerBindingRevision(IntPtr self, ControllerHandle_t controllerHandle, ref int pMajor, ref int pMinor);

		internal bool GetControllerBindingRevision(ControllerHandle_t controllerHandle, ref int pMajor, ref int pMinor)
		{
			return _GetControllerBindingRevision(Self, controllerHandle, ref pMajor, ref pMinor);
		}
	}
	internal class ISteamFriends : SteamInterface
	{
		internal ISteamFriends(bool IsGameServer)
		{
			SetupInterface(IsGameServer);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl)]
		internal static extern IntPtr SteamAPI_SteamFriends_v017();

		public override IntPtr GetUserInterfacePointer()
		{
			return SteamAPI_SteamFriends_v017();
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_GetPersonaName")]
		private static extern Utf8StringPointer _GetPersonaName(IntPtr self);

		internal string GetPersonaName()
		{
			Utf8StringPointer utf8StringPointer = _GetPersonaName(Self);
			return utf8StringPointer;
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_SetPersonaName")]
		private static extern SteamAPICall_t _SetPersonaName(IntPtr self, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchPersonaName);

		internal CallResult<SetPersonaNameResponse_t> SetPersonaName([MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchPersonaName)
		{
			SteamAPICall_t call = _SetPersonaName(Self, pchPersonaName);
			return new CallResult<SetPersonaNameResponse_t>(call, base.IsServer);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_GetPersonaState")]
		private static extern FriendState _GetPersonaState(IntPtr self);

		internal FriendState GetPersonaState()
		{
			return _GetPersonaState(Self);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_GetFriendCount")]
		private static extern int _GetFriendCount(IntPtr self, int iFriendFlags);

		internal int GetFriendCount(int iFriendFlags)
		{
			return _GetFriendCount(Self, iFriendFlags);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_GetFriendByIndex")]
		private static extern SteamId _GetFriendByIndex(IntPtr self, int iFriend, int iFriendFlags);

		internal SteamId GetFriendByIndex(int iFriend, int iFriendFlags)
		{
			return _GetFriendByIndex(Self, iFriend, iFriendFlags);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_GetFriendRelationship")]
		private static extern Relationship _GetFriendRelationship(IntPtr self, SteamId steamIDFriend);

		internal Relationship GetFriendRelationship(SteamId steamIDFriend)
		{
			return _GetFriendRelationship(Self, steamIDFriend);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_GetFriendPersonaState")]
		private static extern FriendState _GetFriendPersonaState(IntPtr self, SteamId steamIDFriend);

		internal FriendState GetFriendPersonaState(SteamId steamIDFriend)
		{
			return _GetFriendPersonaState(Self, steamIDFriend);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_GetFriendPersonaName")]
		private static extern Utf8StringPointer _GetFriendPersonaName(IntPtr self, SteamId steamIDFriend);

		internal string GetFriendPersonaName(SteamId steamIDFriend)
		{
			Utf8StringPointer utf8StringPointer = _GetFriendPersonaName(Self, steamIDFriend);
			return utf8StringPointer;
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_GetFriendGamePlayed")]
		[return: MarshalAs(UnmanagedType.I1)]
		private static extern bool _GetFriendGamePlayed(IntPtr self, SteamId steamIDFriend, ref FriendGameInfo_t pFriendGameInfo);

		internal bool GetFriendGamePlayed(SteamId steamIDFriend, ref FriendGameInfo_t pFriendGameInfo)
		{
			return _GetFriendGamePlayed(Self, steamIDFriend, ref pFriendGameInfo);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_GetFriendPersonaNameHistory")]
		private static extern Utf8StringPointer _GetFriendPersonaNameHistory(IntPtr self, SteamId steamIDFriend, int iPersonaName);

		internal string GetFriendPersonaNameHistory(SteamId steamIDFriend, int iPersonaName)
		{
			Utf8StringPointer utf8StringPointer = _GetFriendPersonaNameHistory(Self, steamIDFriend, iPersonaName);
			return utf8StringPointer;
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_GetFriendSteamLevel")]
		private static extern int _GetFriendSteamLevel(IntPtr self, SteamId steamIDFriend);

		internal int GetFriendSteamLevel(SteamId steamIDFriend)
		{
			return _GetFriendSteamLevel(Self, steamIDFriend);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_GetPlayerNickname")]
		private static extern Utf8StringPointer _GetPlayerNickname(IntPtr self, SteamId steamIDPlayer);

		internal string GetPlayerNickname(SteamId steamIDPlayer)
		{
			Utf8StringPointer utf8StringPointer = _GetPlayerNickname(Self, steamIDPlayer);
			return utf8StringPointer;
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_GetFriendsGroupCount")]
		private static extern int _GetFriendsGroupCount(IntPtr self);

		internal int GetFriendsGroupCount()
		{
			return _GetFriendsGroupCount(Self);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_GetFriendsGroupIDByIndex")]
		private static extern FriendsGroupID_t _GetFriendsGroupIDByIndex(IntPtr self, int iFG);

		internal FriendsGroupID_t GetFriendsGroupIDByIndex(int iFG)
		{
			return _GetFriendsGroupIDByIndex(Self, iFG);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_GetFriendsGroupName")]
		private static extern Utf8StringPointer _GetFriendsGroupName(IntPtr self, FriendsGroupID_t friendsGroupID);

		internal string GetFriendsGroupName(FriendsGroupID_t friendsGroupID)
		{
			Utf8StringPointer utf8StringPointer = _GetFriendsGroupName(Self, friendsGroupID);
			return utf8StringPointer;
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_GetFriendsGroupMembersCount")]
		private static extern int _GetFriendsGroupMembersCount(IntPtr self, FriendsGroupID_t friendsGroupID);

		internal int GetFriendsGroupMembersCount(FriendsGroupID_t friendsGroupID)
		{
			return _GetFriendsGroupMembersCount(Self, friendsGroupID);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_GetFriendsGroupMembersList")]
		private static extern void _GetFriendsGroupMembersList(IntPtr self, FriendsGroupID_t friendsGroupID, [In][Out] SteamId[] pOutSteamIDMembers, int nMembersCount);

		internal void GetFriendsGroupMembersList(FriendsGroupID_t friendsGroupID, [In][Out] SteamId[] pOutSteamIDMembers, int nMembersCount)
		{
			_GetFriendsGroupMembersList(Self, friendsGroupID, pOutSteamIDMembers, nMembersCount);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_HasFriend")]
		[return: MarshalAs(UnmanagedType.I1)]
		private static extern bool _HasFriend(IntPtr self, SteamId steamIDFriend, int iFriendFlags);

		internal bool HasFriend(SteamId steamIDFriend, int iFriendFlags)
		{
			return _HasFriend(Self, steamIDFriend, iFriendFlags);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_GetClanCount")]
		private static extern int _GetClanCount(IntPtr self);

		internal int GetClanCount()
		{
			return _GetClanCount(Self);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_GetClanByIndex")]
		private static extern SteamId _GetClanByIndex(IntPtr self, int iClan);

		internal SteamId GetClanByIndex(int iClan)
		{
			return _GetClanByIndex(Self, iClan);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_GetClanName")]
		private static extern Utf8StringPointer _GetClanName(IntPtr self, SteamId steamIDClan);

		internal string GetClanName(SteamId steamIDClan)
		{
			Utf8StringPointer utf8StringPointer = _GetClanName(Self, steamIDClan);
			return utf8StringPointer;
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_GetClanTag")]
		private static extern Utf8StringPointer _GetClanTag(IntPtr self, SteamId steamIDClan);

		internal string GetClanTag(SteamId steamIDClan)
		{
			Utf8StringPointer utf8StringPointer = _GetClanTag(Self, steamIDClan);
			return utf8StringPointer;
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_GetClanActivityCounts")]
		[return: MarshalAs(UnmanagedType.I1)]
		private static extern bool _GetClanActivityCounts(IntPtr self, SteamId steamIDClan, ref int pnOnline, ref int pnInGame, ref int pnChatting);

		internal bool GetClanActivityCounts(SteamId steamIDClan, ref int pnOnline, ref int pnInGame, ref int pnChatting)
		{
			return _GetClanActivityCounts(Self, steamIDClan, ref pnOnline, ref pnInGame, ref pnChatting);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_DownloadClanActivityCounts")]
		private static extern SteamAPICall_t _DownloadClanActivityCounts(IntPtr self, [In][Out] SteamId[] psteamIDClans, int cClansToRequest);

		internal CallResult<DownloadClanActivityCountsResult_t> DownloadClanActivityCounts([In][Out] SteamId[] psteamIDClans, int cClansToRequest)
		{
			SteamAPICall_t call = _DownloadClanActivityCounts(Self, psteamIDClans, cClansToRequest);
			return new CallResult<DownloadClanActivityCountsResult_t>(call, base.IsServer);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_GetFriendCountFromSource")]
		private static extern int _GetFriendCountFromSource(IntPtr self, SteamId steamIDSource);

		internal int GetFriendCountFromSource(SteamId steamIDSource)
		{
			return _GetFriendCountFromSource(Self, steamIDSource);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_GetFriendFromSourceByIndex")]
		private static extern SteamId _GetFriendFromSourceByIndex(IntPtr self, SteamId steamIDSource, int iFriend);

		internal SteamId GetFriendFromSourceByIndex(SteamId steamIDSource, int iFriend)
		{
			return _GetFriendFromSourceByIndex(Self, steamIDSource, iFriend);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_IsUserInSource")]
		[return: MarshalAs(UnmanagedType.I1)]
		private static extern bool _IsUserInSource(IntPtr self, SteamId steamIDUser, SteamId steamIDSource);

		internal bool IsUserInSource(SteamId steamIDUser, SteamId steamIDSource)
		{
			return _IsUserInSource(Self, steamIDUser, steamIDSource);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_SetInGameVoiceSpeaking")]
		private static extern void _SetInGameVoiceSpeaking(IntPtr self, SteamId steamIDUser, [MarshalAs(UnmanagedType.U1)] bool bSpeaking);

		internal void SetInGameVoiceSpeaking(SteamId steamIDUser, [MarshalAs(UnmanagedType.U1)] bool bSpeaking)
		{
			_SetInGameVoiceSpeaking(Self, steamIDUser, bSpeaking);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_ActivateGameOverlay")]
		private static extern void _ActivateGameOverlay(IntPtr self, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchDialog);

		internal void ActivateGameOverlay([MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchDialog)
		{
			_ActivateGameOverlay(Self, pchDialog);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_ActivateGameOverlayToUser")]
		private static extern void _ActivateGameOverlayToUser(IntPtr self, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchDialog, SteamId steamID);

		internal void ActivateGameOverlayToUser([MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchDialog, SteamId steamID)
		{
			_ActivateGameOverlayToUser(Self, pchDialog, steamID);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_ActivateGameOverlayToWebPage")]
		private static extern void _ActivateGameOverlayToWebPage(IntPtr self, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchURL, ActivateGameOverlayToWebPageMode eMode);

		internal void ActivateGameOverlayToWebPage([MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "Steamworks.Utf8StringToNative")] string pchURL, ActivateGameOverlayToWebPageMode eMode)
		{
			_ActivateGameOverlayToWebPage(Self, pchURL, eMode);
		}

		[DllImport("steam_api64", CallingConvention = CallingConvention.Cdecl, EntryPoint = "SteamAPI_ISteamFriends_ActivateGameOverlayToStore")]
		private static extern void _ActivateGameOverlayToStore(IntPtr self, AppId nAppID, OverlayToStoreFlag eFlag);

		inte

Mods/LiteNetLib.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics.Arm;
using System.Runtime.Intrinsics.X86;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using LiteNetLib.Layers;
using LiteNetLib.Utils;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyMetadata("IsTrimmable", "True")]
[assembly: AssemblyCompany("Ruslan Pyrch")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright 2024 Ruslan Pyrch")]
[assembly: AssemblyDescription("Lite reliable UDP library for .NET, Mono, and .NET Core")]
[assembly: AssemblyFileVersion("1.3.1")]
[assembly: AssemblyInformationalVersion("1.0.0+f57b9eafe72b924681a371d671af911478b6ab88")]
[assembly: AssemblyProduct("LiteNetLib")]
[assembly: AssemblyTitle("LiteNetLib")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/RevenantX/LiteNetLib")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.3.1.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class IsUnmanagedAttribute : Attribute
	{
	}
}
namespace LiteNetLib
{
	internal abstract class BaseChannel
	{
		protected readonly NetPeer Peer;

		protected readonly Queue<NetPacket> OutgoingQueue = new Queue<NetPacket>(64);

		private int _isAddedToPeerChannelSendQueue;

		public int PacketsInQueue => OutgoingQueue.Count;

		protected BaseChannel(NetPeer peer)
		{
			Peer = peer;
		}

		public void AddToQueue(NetPacket packet)
		{
			lock (OutgoingQueue)
			{
				OutgoingQueue.Enqueue(packet);
			}
			AddToPeerChannelSendQueue();
		}

		protected void AddToPeerChannelSendQueue()
		{
			if (Interlocked.CompareExchange(ref _isAddedToPeerChannelSendQueue, 1, 0) == 0)
			{
				Peer.AddToReliableChannelSendQueue(this);
			}
		}

		public bool SendAndCheckQueue()
		{
			bool num = SendNextPackets();
			if (!num)
			{
				Interlocked.Exchange(ref _isAddedToPeerChannelSendQueue, 0);
			}
			return num;
		}

		protected abstract bool SendNextPackets();

		public abstract bool ProcessPacket(NetPacket packet);
	}
	internal enum ConnectionRequestResult
	{
		None,
		Accept,
		Reject,
		RejectForce
	}
	public class ConnectionRequest
	{
		private readonly NetManager _listener;

		private int _used;

		internal NetConnectRequestPacket InternalPacket;

		public readonly IPEndPoint RemoteEndPoint;

		public NetDataReader Data => InternalPacket.Data;

		internal ConnectionRequestResult Result { get; private set; }

		internal void UpdateRequest(NetConnectRequestPacket connectRequest)
		{
			if (connectRequest.ConnectionTime >= InternalPacket.ConnectionTime && (connectRequest.ConnectionTime != InternalPacket.ConnectionTime || connectRequest.ConnectionNumber != InternalPacket.ConnectionNumber))
			{
				InternalPacket = connectRequest;
			}
		}

		private bool TryActivate()
		{
			return Interlocked.CompareExchange(ref _used, 1, 0) == 0;
		}

		internal ConnectionRequest(IPEndPoint remoteEndPoint, NetConnectRequestPacket requestPacket, NetManager listener)
		{
			InternalPacket = requestPacket;
			RemoteEndPoint = remoteEndPoint;
			_listener = listener;
		}

		public NetPeer AcceptIfKey(string key)
		{
			if (!TryActivate())
			{
				return null;
			}
			try
			{
				if (Data.GetString() == key)
				{
					Result = ConnectionRequestResult.Accept;
				}
			}
			catch
			{
				NetDebug.WriteError("[AC] Invalid incoming data");
			}
			if (Result == ConnectionRequestResult.Accept)
			{
				return _listener.OnConnectionSolved(this, null, 0, 0);
			}
			Result = ConnectionRequestResult.Reject;
			_listener.OnConnectionSolved(this, null, 0, 0);
			return null;
		}

		public NetPeer Accept()
		{
			if (!TryActivate())
			{
				return null;
			}
			Result = ConnectionRequestResult.Accept;
			return _listener.OnConnectionSolved(this, null, 0, 0);
		}

		public void Reject(byte[] rejectData, int start, int length, bool force)
		{
			if (TryActivate())
			{
				Result = (force ? ConnectionRequestResult.RejectForce : ConnectionRequestResult.Reject);
				_listener.OnConnectionSolved(this, rejectData, start, length);
			}
		}

		public void Reject(byte[] rejectData, int start, int length)
		{
			Reject(rejectData, start, length, force: false);
		}

		public void RejectForce(byte[] rejectData, int start, int length)
		{
			Reject(rejectData, start, length, force: true);
		}

		public void RejectForce()
		{
			Reject(null, 0, 0, force: true);
		}

		public void RejectForce(byte[] rejectData)
		{
			Reject(rejectData, 0, rejectData.Length, force: true);
		}

		public void RejectForce(NetDataWriter rejectData)
		{
			Reject(rejectData.Data, 0, rejectData.Length, force: true);
		}

		public void Reject()
		{
			Reject(null, 0, 0, force: false);
		}

		public void Reject(byte[] rejectData)
		{
			Reject(rejectData, 0, rejectData.Length, force: false);
		}

		public void Reject(NetDataWriter rejectData)
		{
			Reject(rejectData.Data, 0, rejectData.Length, force: false);
		}
	}
	public enum UnconnectedMessageType
	{
		BasicMessage,
		Broadcast
	}
	public enum DisconnectReason
	{
		ConnectionFailed,
		Timeout,
		HostUnreachable,
		NetworkUnreachable,
		RemoteConnectionClose,
		DisconnectPeerCalled,
		ConnectionRejected,
		InvalidProtocol,
		UnknownHost,
		Reconnect,
		PeerToPeerConnection,
		PeerNotFound
	}
	public struct DisconnectInfo
	{
		public DisconnectReason Reason;

		public SocketError SocketErrorCode;

		public NetPacketReader AdditionalData;
	}
	public interface INetEventListener
	{
		void OnPeerConnected(NetPeer peer);

		void OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo);

		void OnNetworkError(IPEndPoint endPoint, SocketError socketError);

		void OnNetworkReceive(NetPeer peer, NetPacketReader reader, byte channelNumber, DeliveryMethod deliveryMethod);

		void OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketReader reader, UnconnectedMessageType messageType);

		void OnNetworkLatencyUpdate(NetPeer peer, int latency);

		void OnConnectionRequest(ConnectionRequest request);
	}
	public interface IDeliveryEventListener
	{
		void OnMessageDelivered(NetPeer peer, object userData);
	}
	public interface INtpEventListener
	{
		void OnNtpResponse(NtpPacket packet);
	}
	public interface IPeerAddressChangedListener
	{
		void OnPeerAddressChanged(NetPeer peer, IPEndPoint previousAddress);
	}
	public class EventBasedNetListener : INetEventListener, IDeliveryEventListener, INtpEventListener, IPeerAddressChangedListener
	{
		public delegate void OnPeerConnected(NetPeer peer);

		public delegate void OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo);

		public delegate void OnNetworkError(IPEndPoint endPoint, SocketError socketError);

		public delegate void OnNetworkReceive(NetPeer peer, NetPacketReader reader, byte channel, DeliveryMethod deliveryMethod);

		public delegate void OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketReader reader, UnconnectedMessageType messageType);

		public delegate void OnNetworkLatencyUpdate(NetPeer peer, int latency);

		public delegate void OnConnectionRequest(ConnectionRequest request);

		public delegate void OnDeliveryEvent(NetPeer peer, object userData);

		public delegate void OnNtpResponseEvent(NtpPacket packet);

		public delegate void OnPeerAddressChangedEvent(NetPeer peer, IPEndPoint previousAddress);

		public event OnPeerConnected PeerConnectedEvent;

		public event OnPeerDisconnected PeerDisconnectedEvent;

		public event OnNetworkError NetworkErrorEvent;

		public event OnNetworkReceive NetworkReceiveEvent;

		public event OnNetworkReceiveUnconnected NetworkReceiveUnconnectedEvent;

		public event OnNetworkLatencyUpdate NetworkLatencyUpdateEvent;

		public event OnConnectionRequest ConnectionRequestEvent;

		public event OnDeliveryEvent DeliveryEvent;

		public event OnNtpResponseEvent NtpResponseEvent;

		public event OnPeerAddressChangedEvent PeerAddressChangedEvent;

		public void ClearPeerConnectedEvent()
		{
			this.PeerConnectedEvent = null;
		}

		public void ClearPeerDisconnectedEvent()
		{
			this.PeerDisconnectedEvent = null;
		}

		public void ClearNetworkErrorEvent()
		{
			this.NetworkErrorEvent = null;
		}

		public void ClearNetworkReceiveEvent()
		{
			this.NetworkReceiveEvent = null;
		}

		public void ClearNetworkReceiveUnconnectedEvent()
		{
			this.NetworkReceiveUnconnectedEvent = null;
		}

		public void ClearNetworkLatencyUpdateEvent()
		{
			this.NetworkLatencyUpdateEvent = null;
		}

		public void ClearConnectionRequestEvent()
		{
			this.ConnectionRequestEvent = null;
		}

		public void ClearDeliveryEvent()
		{
			this.DeliveryEvent = null;
		}

		public void ClearNtpResponseEvent()
		{
			this.NtpResponseEvent = null;
		}

		public void ClearPeerAddressChangedEvent()
		{
			this.PeerAddressChangedEvent = null;
		}

		void INetEventListener.OnPeerConnected(NetPeer peer)
		{
			if (this.PeerConnectedEvent != null)
			{
				this.PeerConnectedEvent(peer);
			}
		}

		void INetEventListener.OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo)
		{
			if (this.PeerDisconnectedEvent != null)
			{
				this.PeerDisconnectedEvent(peer, disconnectInfo);
			}
		}

		void INetEventListener.OnNetworkError(IPEndPoint endPoint, SocketError socketErrorCode)
		{
			if (this.NetworkErrorEvent != null)
			{
				this.NetworkErrorEvent(endPoint, socketErrorCode);
			}
		}

		void INetEventListener.OnNetworkReceive(NetPeer peer, NetPacketReader reader, byte channelNumber, DeliveryMethod deliveryMethod)
		{
			if (this.NetworkReceiveEvent != null)
			{
				this.NetworkReceiveEvent(peer, reader, channelNumber, deliveryMethod);
			}
		}

		void INetEventListener.OnNetworkReceiveUnconnected(IPEndPoint remoteEndPoint, NetPacketReader reader, UnconnectedMessageType messageType)
		{
			if (this.NetworkReceiveUnconnectedEvent != null)
			{
				this.NetworkReceiveUnconnectedEvent(remoteEndPoint, reader, messageType);
			}
		}

		void INetEventListener.OnNetworkLatencyUpdate(NetPeer peer, int latency)
		{
			if (this.NetworkLatencyUpdateEvent != null)
			{
				this.NetworkLatencyUpdateEvent(peer, latency);
			}
		}

		void INetEventListener.OnConnectionRequest(ConnectionRequest request)
		{
			if (this.ConnectionRequestEvent != null)
			{
				this.ConnectionRequestEvent(request);
			}
		}

		void IDeliveryEventListener.OnMessageDelivered(NetPeer peer, object userData)
		{
			if (this.DeliveryEvent != null)
			{
				this.DeliveryEvent(peer, userData);
			}
		}

		void INtpEventListener.OnNtpResponse(NtpPacket packet)
		{
			if (this.NtpResponseEvent != null)
			{
				this.NtpResponseEvent(packet);
			}
		}

		void IPeerAddressChangedListener.OnPeerAddressChanged(NetPeer peer, IPEndPoint previousAddress)
		{
			if (this.PeerAddressChangedEvent != null)
			{
				this.PeerAddressChangedEvent(peer, previousAddress);
			}
		}
	}
	internal sealed class NetConnectRequestPacket
	{
		public const int HeaderSize = 18;

		public readonly long ConnectionTime;

		public byte ConnectionNumber;

		public readonly byte[] TargetAddress;

		public readonly NetDataReader Data;

		public readonly int PeerId;

		private NetConnectRequestPacket(long connectionTime, byte connectionNumber, int localId, byte[] targetAddress, NetDataReader data)
		{
			ConnectionTime = connectionTime;
			ConnectionNumber = connectionNumber;
			TargetAddress = targetAddress;
			Data = data;
			PeerId = localId;
		}

		public static int GetProtocolId(NetPacket packet)
		{
			return BitConverter.ToInt32(packet.RawData, 1);
		}

		public static NetConnectRequestPacket FromData(NetPacket packet)
		{
			if (packet.ConnectionNumber >= 4)
			{
				return null;
			}
			long connectionTime = BitConverter.ToInt64(packet.RawData, 5);
			int localId = BitConverter.ToInt32(packet.RawData, 13);
			int num = packet.RawData[17];
			if (num != 16 && num != 28)
			{
				return null;
			}
			byte[] array = new byte[num];
			Buffer.BlockCopy(packet.RawData, 18, array, 0, num);
			NetDataReader netDataReader = new NetDataReader(null, 0, 0);
			if (packet.Size > 18 + num)
			{
				netDataReader.SetSource(packet.RawData, 18 + num, packet.Size);
			}
			return new NetConnectRequestPacket(connectionTime, packet.ConnectionNumber, localId, array, netDataReader);
		}

		public static NetPacket Make(NetDataWriter connectData, SocketAddress addressBytes, long connectTime, int localId)
		{
			NetPacket netPacket = new NetPacket(PacketProperty.ConnectRequest, connectData.Length + addressBytes.Size);
			FastBitConverter.GetBytes(netPacket.RawData, 1, 13);
			FastBitConverter.GetBytes(netPacket.RawData, 5, connectTime);
			FastBitConverter.GetBytes(netPacket.RawData, 13, localId);
			netPacket.RawData[17] = (byte)addressBytes.Size;
			for (int i = 0; i < addressBytes.Size; i++)
			{
				netPacket.RawData[18 + i] = addressBytes[i];
			}
			Buffer.BlockCopy(connectData.Data, 0, netPacket.RawData, 18 + addressBytes.Size, connectData.Length);
			return netPacket;
		}
	}
	internal sealed class NetConnectAcceptPacket
	{
		public const int Size = 15;

		public readonly long ConnectionTime;

		public readonly byte ConnectionNumber;

		public readonly int PeerId;

		public readonly bool PeerNetworkChanged;

		private NetConnectAcceptPacket(long connectionTime, byte connectionNumber, int peerId, bool peerNetworkChanged)
		{
			ConnectionTime = connectionTime;
			ConnectionNumber = connectionNumber;
			PeerId = peerId;
			PeerNetworkChanged = peerNetworkChanged;
		}

		public static NetConnectAcceptPacket FromData(NetPacket packet)
		{
			if (packet.Size != 15)
			{
				return null;
			}
			long connectionTime = BitConverter.ToInt64(packet.RawData, 1);
			byte b = packet.RawData[9];
			if (b >= 4)
			{
				return null;
			}
			byte b2 = packet.RawData[10];
			if (b2 > 1)
			{
				return null;
			}
			int num = BitConverter.ToInt32(packet.RawData, 11);
			if (num < 0)
			{
				return null;
			}
			return new NetConnectAcceptPacket(connectionTime, b, num, b2 == 1);
		}

		public static NetPacket Make(long connectTime, byte connectNum, int localPeerId)
		{
			NetPacket netPacket = new NetPacket(PacketProperty.ConnectAccept, 0);
			FastBitConverter.GetBytes(netPacket.RawData, 1, connectTime);
			netPacket.RawData[9] = connectNum;
			FastBitConverter.GetBytes(netPacket.RawData, 11, localPeerId);
			return netPacket;
		}

		public static NetPacket MakeNetworkChanged(NetPeer peer)
		{
			NetPacket netPacket = new NetPacket(PacketProperty.PeerNotFound, 14);
			FastBitConverter.GetBytes(netPacket.RawData, 1, peer.ConnectTime);
			netPacket.RawData[9] = peer.ConnectionNum;
			netPacket.RawData[10] = 1;
			FastBitConverter.GetBytes(netPacket.RawData, 11, peer.RemoteId);
			return netPacket;
		}
	}
	internal static class NativeSocket
	{
		private static class WinSock
		{
			private const string LibName = "ws2_32.dll";

			[DllImport("ws2_32.dll", SetLastError = true)]
			public static extern int recvfrom(IntPtr socketHandle, [In][Out] byte[] pinnedBuffer, [In] int len, [In] SocketFlags socketFlags, [Out] byte[] socketAddress, [In][Out] ref int socketAddressSize);

			[DllImport("ws2_32.dll", SetLastError = true)]
			internal unsafe static extern int sendto(IntPtr socketHandle, byte* pinnedBuffer, [In] int len, [In] SocketFlags socketFlags, [In] byte[] socketAddress, [In] int socketAddressSize);
		}

		private static class UnixSock
		{
			private const string LibName = "libc";

			[DllImport("libc", SetLastError = true)]
			public static extern int recvfrom(IntPtr socketHandle, [In][Out] byte[] pinnedBuffer, [In] int len, [In] SocketFlags socketFlags, [Out] byte[] socketAddress, [In][Out] ref int socketAddressSize);

			[DllImport("libc", SetLastError = true)]
			internal unsafe static extern int sendto(IntPtr socketHandle, byte* pinnedBuffer, [In] int len, [In] SocketFlags socketFlags, [In] byte[] socketAddress, [In] int socketAddressSize);
		}

		public static readonly bool IsSupported;

		public static readonly bool UnixMode;

		public const int IPv4AddrSize = 16;

		public const int IPv6AddrSize = 28;

		public const int AF_INET = 2;

		public const int AF_INET6 = 10;

		private static readonly Dictionary<int, SocketError> NativeErrorToSocketError;

		static NativeSocket()
		{
			IsSupported = false;
			UnixMode = false;
			NativeErrorToSocketError = new Dictionary<int, SocketError>
			{
				{
					13,
					SocketError.AccessDenied
				},
				{
					98,
					SocketError.AddressAlreadyInUse
				},
				{
					99,
					SocketError.AddressNotAvailable
				},
				{
					97,
					SocketError.AddressFamilyNotSupported
				},
				{
					11,
					SocketError.WouldBlock
				},
				{
					114,
					SocketError.AlreadyInProgress
				},
				{
					9,
					SocketError.OperationAborted
				},
				{
					125,
					SocketError.OperationAborted
				},
				{
					103,
					SocketError.ConnectionAborted
				},
				{
					111,
					SocketError.ConnectionRefused
				},
				{
					104,
					SocketError.ConnectionReset
				},
				{
					89,
					SocketError.DestinationAddressRequired
				},
				{
					14,
					SocketError.Fault
				},
				{
					112,
					SocketError.HostDown
				},
				{
					6,
					SocketError.HostNotFound
				},
				{
					113,
					SocketError.HostUnreachable
				},
				{
					115,
					SocketError.InProgress
				},
				{
					4,
					SocketError.Interrupted
				},
				{
					22,
					SocketError.InvalidArgument
				},
				{
					106,
					SocketError.IsConnected
				},
				{
					24,
					SocketError.TooManyOpenSockets
				},
				{
					90,
					SocketError.MessageSize
				},
				{
					100,
					SocketError.NetworkDown
				},
				{
					102,
					SocketError.NetworkReset
				},
				{
					101,
					SocketError.NetworkUnreachable
				},
				{
					23,
					SocketError.TooManyOpenSockets
				},
				{
					105,
					SocketError.NoBufferSpaceAvailable
				},
				{
					61,
					SocketError.NoData
				},
				{
					2,
					SocketError.AddressNotAvailable
				},
				{
					92,
					SocketError.ProtocolOption
				},
				{
					107,
					SocketError.NotConnected
				},
				{
					88,
					SocketError.NotSocket
				},
				{
					3440,
					SocketError.OperationNotSupported
				},
				{
					1,
					SocketError.AccessDenied
				},
				{
					32,
					SocketError.Shutdown
				},
				{
					96,
					SocketError.ProtocolFamilyNotSupported
				},
				{
					93,
					SocketError.ProtocolNotSupported
				},
				{
					91,
					SocketError.ProtocolType
				},
				{
					94,
					SocketError.SocketNotSupported
				},
				{
					108,
					SocketError.Disconnecting
				},
				{
					110,
					SocketError.TimedOut
				},
				{
					0,
					SocketError.Success
				}
			};
			if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
			{
				IsSupported = true;
				UnixMode = true;
			}
			else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
			{
				IsSupported = true;
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static int RecvFrom(IntPtr socketHandle, byte[] pinnedBuffer, int len, byte[] socketAddress, ref int socketAddressSize)
		{
			if (!UnixMode)
			{
				return WinSock.recvfrom(socketHandle, pinnedBuffer, len, SocketFlags.None, socketAddress, ref socketAddressSize);
			}
			return UnixSock.recvfrom(socketHandle, pinnedBuffer, len, SocketFlags.None, socketAddress, ref socketAddressSize);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public unsafe static int SendTo(IntPtr socketHandle, byte* pinnedBuffer, int len, byte[] socketAddress, int socketAddressSize)
		{
			if (!UnixMode)
			{
				return WinSock.sendto(socketHandle, pinnedBuffer, len, SocketFlags.None, socketAddress, socketAddressSize);
			}
			return UnixSock.sendto(socketHandle, pinnedBuffer, len, SocketFlags.None, socketAddress, socketAddressSize);
		}

		public static SocketError GetSocketError()
		{
			int lastWin32Error = Marshal.GetLastWin32Error();
			if (UnixMode)
			{
				if (!NativeErrorToSocketError.TryGetValue(lastWin32Error, out var value))
				{
					return SocketError.SocketError;
				}
				return value;
			}
			return (SocketError)lastWin32Error;
		}

		public static SocketException GetSocketException()
		{
			int lastWin32Error = Marshal.GetLastWin32Error();
			if (UnixMode)
			{
				if (!NativeErrorToSocketError.TryGetValue(lastWin32Error, out var value))
				{
					return new SocketException(-1);
				}
				return new SocketException((int)value);
			}
			return new SocketException(lastWin32Error);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public static short GetNativeAddressFamily(IPEndPoint remoteEndPoint)
		{
			if (!UnixMode)
			{
				return (short)remoteEndPoint.AddressFamily;
			}
			return (short)((remoteEndPoint.AddressFamily == AddressFamily.InterNetwork) ? 2 : 10);
		}
	}
	public enum NatAddressType
	{
		Internal,
		External
	}
	public interface INatPunchListener
	{
		void OnNatIntroductionRequest(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, string token);

		void OnNatIntroductionSuccess(IPEndPoint targetEndPoint, NatAddressType type, string token);
	}
	public class EventBasedNatPunchListener : INatPunchListener
	{
		public delegate void OnNatIntroductionRequest(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, string token);

		public delegate void OnNatIntroductionSuccess(IPEndPoint targetEndPoint, NatAddressType type, string token);

		public event OnNatIntroductionRequest NatIntroductionRequest;

		public event OnNatIntroductionSuccess NatIntroductionSuccess;

		void INatPunchListener.OnNatIntroductionRequest(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, string token)
		{
			if (this.NatIntroductionRequest != null)
			{
				this.NatIntroductionRequest(localEndPoint, remoteEndPoint, token);
			}
		}

		void INatPunchListener.OnNatIntroductionSuccess(IPEndPoint targetEndPoint, NatAddressType type, string token)
		{
			if (this.NatIntroductionSuccess != null)
			{
				this.NatIntroductionSuccess(targetEndPoint, type, token);
			}
		}
	}
	public sealed class NatPunchModule
	{
		private struct RequestEventData
		{
			public IPEndPoint LocalEndPoint;

			public IPEndPoint RemoteEndPoint;

			public string Token;
		}

		private struct SuccessEventData
		{
			public IPEndPoint TargetEndPoint;

			public NatAddressType Type;

			public string Token;
		}

		private class NatIntroduceRequestPacket
		{
			public IPEndPoint Internal
			{
				[Preserve]
				get;
				[Preserve]
				set;
			}

			public string Token
			{
				[Preserve]
				get;
				[Preserve]
				set;
			}
		}

		private class NatIntroduceResponsePacket
		{
			public IPEndPoint Internal
			{
				[Preserve]
				get;
				[Preserve]
				set;
			}

			public IPEndPoint External
			{
				[Preserve]
				get;
				[Preserve]
				set;
			}

			public string Token
			{
				[Preserve]
				get;
				[Preserve]
				set;
			}
		}

		private class NatPunchPacket
		{
			public string Token
			{
				[Preserve]
				get;
				[Preserve]
				set;
			}

			public bool IsExternal
			{
				[Preserve]
				get;
				[Preserve]
				set;
			}
		}

		private readonly NetManager _socket;

		private readonly ConcurrentQueue<RequestEventData> _requestEvents = new ConcurrentQueue<RequestEventData>();

		private readonly ConcurrentQueue<SuccessEventData> _successEvents = new ConcurrentQueue<SuccessEventData>();

		private readonly NetDataReader _cacheReader = new NetDataReader();

		private readonly NetDataWriter _cacheWriter = new NetDataWriter();

		private readonly NetPacketProcessor _netPacketProcessor = new NetPacketProcessor(256);

		private INatPunchListener _natPunchListener;

		public const int MaxTokenLength = 256;

		public bool UnsyncedEvents;

		internal NatPunchModule(NetManager socket)
		{
			_socket = socket;
			_netPacketProcessor.SubscribeReusable<NatIntroduceResponsePacket>(OnNatIntroductionResponse);
			_netPacketProcessor.SubscribeReusable<NatIntroduceRequestPacket, IPEndPoint>(OnNatIntroductionRequest);
			_netPacketProcessor.SubscribeReusable<NatPunchPacket, IPEndPoint>(OnNatPunch);
		}

		internal void ProcessMessage(IPEndPoint senderEndPoint, NetPacket packet)
		{
			lock (_cacheReader)
			{
				_cacheReader.SetSource(packet.RawData, 1, packet.Size);
				_netPacketProcessor.ReadAllPackets(_cacheReader, senderEndPoint);
			}
		}

		public void Init(INatPunchListener listener)
		{
			_natPunchListener = listener;
		}

		private void Send<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)] T>(T packet, IPEndPoint target) where T : class, new()
		{
			_cacheWriter.Reset();
			_cacheWriter.Put((byte)16);
			_netPacketProcessor.Write(_cacheWriter, packet);
			_socket.SendRaw(_cacheWriter.Data, 0, _cacheWriter.Length, target);
		}

		public void NatIntroduce(IPEndPoint hostInternal, IPEndPoint hostExternal, IPEndPoint clientInternal, IPEndPoint clientExternal, string additionalInfo)
		{
			NatIntroduceResponsePacket natIntroduceResponsePacket = new NatIntroduceResponsePacket
			{
				Token = additionalInfo
			};
			natIntroduceResponsePacket.Internal = hostInternal;
			natIntroduceResponsePacket.External = hostExternal;
			Send(natIntroduceResponsePacket, clientExternal);
			natIntroduceResponsePacket.Internal = clientInternal;
			natIntroduceResponsePacket.External = clientExternal;
			Send(natIntroduceResponsePacket, hostExternal);
		}

		public void PollEvents()
		{
			if (!UnsyncedEvents && _natPunchListener != null && (!_successEvents.IsEmpty || !_requestEvents.IsEmpty))
			{
				SuccessEventData result;
				while (_successEvents.TryDequeue(out result))
				{
					_natPunchListener.OnNatIntroductionSuccess(result.TargetEndPoint, result.Type, result.Token);
				}
				RequestEventData result2;
				while (_requestEvents.TryDequeue(out result2))
				{
					_natPunchListener.OnNatIntroductionRequest(result2.LocalEndPoint, result2.RemoteEndPoint, result2.Token);
				}
			}
		}

		public void SendNatIntroduceRequest(string host, int port, string additionalInfo)
		{
			SendNatIntroduceRequest(NetUtils.MakeEndPoint(host, port), additionalInfo);
		}

		public void SendNatIntroduceRequest(IPEndPoint masterServerEndPoint, string additionalInfo)
		{
			string localIp = NetUtils.GetLocalIp(LocalAddrType.IPv4);
			if (string.IsNullOrEmpty(localIp) || masterServerEndPoint.AddressFamily == AddressFamily.InterNetworkV6)
			{
				localIp = NetUtils.GetLocalIp(LocalAddrType.IPv6);
			}
			Send(new NatIntroduceRequestPacket
			{
				Internal = NetUtils.MakeEndPoint(localIp, _socket.LocalPort),
				Token = additionalInfo
			}, masterServerEndPoint);
		}

		private void OnNatIntroductionRequest(NatIntroduceRequestPacket req, IPEndPoint senderEndPoint)
		{
			if (UnsyncedEvents)
			{
				_natPunchListener.OnNatIntroductionRequest(req.Internal, senderEndPoint, req.Token);
				return;
			}
			_requestEvents.Enqueue(new RequestEventData
			{
				LocalEndPoint = req.Internal,
				RemoteEndPoint = senderEndPoint,
				Token = req.Token
			});
		}

		private void OnNatIntroductionResponse(NatIntroduceResponsePacket req)
		{
			NatPunchPacket natPunchPacket = new NatPunchPacket
			{
				Token = req.Token
			};
			Send(natPunchPacket, req.Internal);
			_socket.Ttl = 2;
			_socket.SendRaw(new byte[1] { 17 }, 0, 1, req.External);
			_socket.Ttl = 255;
			natPunchPacket.IsExternal = true;
			Send(natPunchPacket, req.External);
		}

		private void OnNatPunch(NatPunchPacket req, IPEndPoint senderEndPoint)
		{
			if (UnsyncedEvents)
			{
				_natPunchListener.OnNatIntroductionSuccess(senderEndPoint, req.IsExternal ? NatAddressType.External : NatAddressType.Internal, req.Token);
				return;
			}
			_successEvents.Enqueue(new SuccessEventData
			{
				TargetEndPoint = senderEndPoint,
				Type = (req.IsExternal ? NatAddressType.External : NatAddressType.Internal),
				Token = req.Token
			});
		}
	}
	public enum DeliveryMethod : byte
	{
		Unreliable = 4,
		ReliableUnordered = 0,
		Sequenced = 1,
		ReliableOrdered = 2,
		ReliableSequenced = 3
	}
	public static class NetConstants
	{
		public const int DefaultWindowSize = 64;

		public const int SocketBufferSize = 1048576;

		public const int SocketTTL = 255;

		public const int HeaderSize = 1;

		public const int ChanneledHeaderSize = 4;

		public const int FragmentHeaderSize = 6;

		public const int FragmentedHeaderTotalSize = 10;

		public const ushort MaxSequence = 32768;

		public const ushort HalfMaxSequence = 16384;

		internal const int ProtocolId = 13;

		internal const int MaxUdpHeaderSize = 68;

		internal const int ChannelTypeCount = 4;

		internal static readonly int[] PossibleMtu = new int[6] { 1024, 1164, 1392, 1404, 1424, 1432 };

		public static readonly int InitialMtu = PossibleMtu[0];

		public static readonly int MaxPacketSize = PossibleMtu[PossibleMtu.Length - 1];

		public static readonly int MaxUnreliableDataSize = MaxPacketSize - 1;

		public const byte MaxConnectionNumber = 4;
	}
	public class InvalidPacketException : ArgumentException
	{
		public InvalidPacketException(string message)
			: base(message)
		{
		}
	}
	public class TooBigPacketException : InvalidPacketException
	{
		public TooBigPacketException(string message)
			: base(message)
		{
		}
	}
	public enum NetLogLevel
	{
		Warning,
		Error,
		Trace,
		Info
	}
	public interface INetLogger
	{
		void WriteNet(NetLogLevel level, string str, params object[] args);
	}
	public static class NetDebug
	{
		public static INetLogger Logger = null;

		private static readonly object DebugLogLock = new object();

		private static void WriteLogic(NetLogLevel logLevel, string str, params object[] args)
		{
			lock (DebugLogLock)
			{
				if (Logger == null)
				{
					Console.WriteLine(str, args);
				}
				else
				{
					Logger.WriteNet(logLevel, str, args);
				}
			}
		}

		[Conditional("DEBUG_MESSAGES")]
		internal static void Write(string str)
		{
			WriteLogic(NetLogLevel.Trace, str);
		}

		[Conditional("DEBUG_MESSAGES")]
		internal static void Write(NetLogLevel level, string str)
		{
			WriteLogic(level, str);
		}

		[Conditional("DEBUG_MESSAGES")]
		[Conditional("DEBUG")]
		internal static void WriteForce(string str)
		{
			WriteLogic(NetLogLevel.Trace, str);
		}

		[Conditional("DEBUG_MESSAGES")]
		[Conditional("DEBUG")]
		internal static void WriteForce(NetLogLevel level, string str)
		{
			WriteLogic(level, str);
		}

		internal static void WriteError(string str)
		{
			WriteLogic(NetLogLevel.Error, str);
		}
	}
	public sealed class NetPacketReader : NetDataReader
	{
		private NetPacket _packet;

		private readonly NetManager _manager;

		private readonly NetEvent _evt;

		internal NetPacketReader(NetManager manager, NetEvent evt)
		{
			_manager = manager;
			_evt = evt;
		}

		internal void SetSource(NetPacket packet, int headerSize)
		{
			if (packet != null)
			{
				_packet = packet;
				SetSource(packet.RawData, headerSize, packet.Size);
			}
		}

		internal void RecycleInternal()
		{
			Clear();
			if (_packet != null)
			{
				_manager.PoolRecycle(_packet);
			}
			_packet = null;
			_manager.RecycleEvent(_evt);
		}

		public void Recycle()
		{
			if (!_manager.AutoRecycle)
			{
				RecycleInternal();
			}
		}
	}
	internal sealed class NetEvent
	{
		public enum EType
		{
			Connect,
			Disconnect,
			Receive,
			ReceiveUnconnected,
			Error,
			ConnectionLatencyUpdated,
			Broadcast,
			ConnectionRequest,
			MessageDelivered,
			PeerAddressChanged
		}

		public NetEvent Next;

		public EType Type;

		public NetPeer Peer;

		public IPEndPoint RemoteEndPoint;

		public object UserData;

		public int Latency;

		public SocketError ErrorCode;

		public DisconnectReason DisconnectReason;

		public ConnectionRequest ConnectionRequest;

		public DeliveryMethod DeliveryMethod;

		public byte ChannelNumber;

		public readonly NetPacketReader DataReader;

		public NetEvent(NetManager manager)
		{
			DataReader = new NetPacketReader(manager, this);
		}
	}
	public class NetManager : IEnumerable<NetPeer>, IEnumerable
	{
		public struct NetPeerEnumerator : IEnumerator<NetPeer>, IEnumerator, IDisposable
		{
			private readonly NetPeer _initialPeer;

			private NetPeer _p;

			public NetPeer Current => _p;

			object IEnumerator.Current => _p;

			public NetPeerEnumerator(NetPeer p)
			{
				_initialPeer = p;
				_p = null;
			}

			public void Dispose()
			{
			}

			public bool MoveNext()
			{
				_p = ((_p == null) ? _initialPeer : _p.NextPeer);
				return _p != null;
			}

			public void Reset()
			{
				throw new NotSupportedException();
			}
		}

		private struct IncomingData
		{
			public NetPacket Data;

			public IPEndPoint EndPoint;

			public DateTime TimeWhenGet;
		}

		private struct Slot
		{
			internal int HashCode;

			internal int Next;

			internal NetPeer Value;
		}

		private readonly List<IncomingData> _pingSimulationList = new List<IncomingData>();

		private readonly Random _randomGenerator = new Random();

		private const int MinLatencyThreshold = 5;

		private Thread _logicThread;

		private bool _manualMode;

		private readonly AutoResetEvent _updateTriggerEvent = new AutoResetEvent(initialState: true);

		private NetEvent _pendingEventHead;

		private NetEvent _pendingEventTail;

		private NetEvent _netEventPoolHead;

		private readonly INetEventListener _netEventListener;

		private readonly IDeliveryEventListener _deliveryEventListener;

		private readonly INtpEventListener _ntpEventListener;

		private readonly IPeerAddressChangedListener _peerAddressChangedListener;

		private readonly Dictionary<IPEndPoint, ConnectionRequest> _requestsDict = new Dictionary<IPEndPoint, ConnectionRequest>();

		private readonly ConcurrentDictionary<IPEndPoint, NtpRequest> _ntpRequests = new ConcurrentDictionary<IPEndPoint, NtpRequest>();

		private long _connectedPeersCount;

		private readonly List<NetPeer> _connectedPeerListCache = new List<NetPeer>();

		private readonly PacketLayerBase _extraPacketLayer;

		private int _lastPeerId;

		private ConcurrentQueue<int> _peerIds = new ConcurrentQueue<int>();

		private byte _channelsCount = 1;

		private readonly object _eventLock = new object();

		private bool _dropPacket;

		public bool UnconnectedMessagesEnabled;

		public bool NatPunchEnabled;

		public int UpdateTime = 15;

		public int PingInterval = 1000;

		public int DisconnectTimeout = 5000;

		public bool SimulatePacketLoss;

		public bool SimulateLatency;

		public int SimulationPacketLossChance = 10;

		public int SimulationMinLatency = 30;

		public int SimulationMaxLatency = 100;

		public bool UnsyncedEvents;

		public bool UnsyncedReceiveEvent;

		public bool UnsyncedDeliveryEvent;

		public bool BroadcastReceiveEnabled;

		public int ReconnectDelay = 500;

		public int MaxConnectAttempts = 10;

		public bool ReuseAddress;

		public bool DontRoute;

		public readonly NetStatistics Statistics = new NetStatistics();

		public bool EnableStatistics;

		public readonly NatPunchModule NatPunchModule;

		public bool AutoRecycle;

		public bool IPv6Enabled = true;

		public int MtuOverride;

		public bool MtuDiscovery;

		public bool UseNativeSockets;

		public bool DisconnectOnUnreachable;

		public bool AllowPeerAddressChange;

		private const int MaxPrimeArrayLength = 2147483587;

		private const int HashPrime = 101;

		private const int Lower31BitMask = int.MaxValue;

		private static readonly int[] Primes;

		private int[] _buckets;

		private Slot[] _slots;

		private int _count;

		private int _lastIndex;

		private int _freeList = -1;

		private NetPeer[] _peersArray = new NetPeer[32];

		private readonly ReaderWriterLockSlim _peersLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);

		private volatile NetPeer _headPeer;

		private NetPacket _poolHead;

		private int _poolCount;

		private readonly object _poolLock = new object();

		public int PacketPoolSize = 1000;

		private const int ReceivePollingTime = 500000;

		private Socket _udpSocketv4;

		private Socket _udpSocketv6;

		private Thread _receiveThread;

		private IPEndPoint _bufferEndPointv4;

		private IPEndPoint _bufferEndPointv6;

		private const int SioUdpConnreset = -1744830452;

		private static readonly IPAddress MulticastAddressV6;

		public static readonly bool IPv6Support;

		internal bool NotConnected;

		public bool IsRunning { get; private set; }

		public int LocalPort { get; private set; }

		public NetPeer FirstPeer => _headPeer;

		public byte ChannelsCount
		{
			get
			{
				return _channelsCount;
			}
			set
			{
				if (value < 1 || value > 64)
				{
					throw new ArgumentException("Channels count must be between 1 and 64");
				}
				_channelsCount = value;
			}
		}

		public List<NetPeer> ConnectedPeerList
		{
			get
			{
				GetPeersNonAlloc(_connectedPeerListCache, ConnectionState.Connected);
				return _connectedPeerListCache;
			}
		}

		public int ConnectedPeersCount => (int)Interlocked.Read(ref _connectedPeersCount);

		public int ExtraPacketSizeForLayer => _extraPacketLayer?.ExtraPacketSizeForLayer ?? 0;

		public int PoolCount => _poolCount;

		public short Ttl
		{
			get
			{
				return _udpSocketv4.Ttl;
			}
			internal set
			{
				_udpSocketv4.Ttl = value;
			}
		}

		public NetManager(INetEventListener listener, PacketLayerBase extraPacketLayer = null)
		{
			_netEventListener = listener;
			_deliveryEventListener = listener as IDeliveryEventListener;
			_ntpEventListener = listener as INtpEventListener;
			_peerAddressChangedListener = listener as IPeerAddressChangedListener;
			NatPunchModule = new NatPunchModule(this);
			_extraPacketLayer = extraPacketLayer;
		}

		internal void ConnectionLatencyUpdated(NetPeer fromPeer, int latency)
		{
			CreateEvent(NetEvent.EType.ConnectionLatencyUpdated, fromPeer, null, SocketError.Success, latency, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0);
		}

		internal void MessageDelivered(NetPeer fromPeer, object userData)
		{
			if (_deliveryEventListener != null)
			{
				CreateEvent(NetEvent.EType.MessageDelivered, fromPeer, null, SocketError.Success, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0, null, userData);
			}
		}

		internal void DisconnectPeerForce(NetPeer peer, DisconnectReason reason, SocketError socketErrorCode, NetPacket eventData)
		{
			DisconnectPeer(peer, reason, socketErrorCode, force: true, null, 0, 0, eventData);
		}

		private void DisconnectPeer(NetPeer peer, DisconnectReason reason, SocketError socketErrorCode, bool force, byte[] data, int start, int count, NetPacket eventData)
		{
			switch (peer.Shutdown(data, start, count, force))
			{
			case ShutdownResult.None:
				return;
			case ShutdownResult.WasConnected:
				Interlocked.Decrement(ref _connectedPeersCount);
				break;
			}
			CreateEvent(NetEvent.EType.Disconnect, peer, null, socketErrorCode, 0, reason, null, DeliveryMethod.Unreliable, 0, eventData);
		}

		private void CreateEvent(NetEvent.EType type, NetPeer peer = null, IPEndPoint remoteEndPoint = null, SocketError errorCode = SocketError.Success, int latency = 0, DisconnectReason disconnectReason = DisconnectReason.ConnectionFailed, ConnectionRequest connectionRequest = null, DeliveryMethod deliveryMethod = DeliveryMethod.Unreliable, byte channelNumber = 0, NetPacket readerSource = null, object userData = null)
		{
			bool flag = UnsyncedEvents;
			switch (type)
			{
			case NetEvent.EType.Connect:
				Interlocked.Increment(ref _connectedPeersCount);
				break;
			case NetEvent.EType.MessageDelivered:
				flag = UnsyncedDeliveryEvent;
				break;
			}
			NetEvent netEvent;
			lock (_eventLock)
			{
				netEvent = _netEventPoolHead;
				if (netEvent == null)
				{
					netEvent = new NetEvent(this);
				}
				else
				{
					_netEventPoolHead = netEvent.Next;
				}
			}
			netEvent.Next = null;
			netEvent.Type = type;
			netEvent.DataReader.SetSource(readerSource, readerSource?.GetHeaderSize() ?? 0);
			netEvent.Peer = peer;
			netEvent.RemoteEndPoint = remoteEndPoint;
			netEvent.Latency = latency;
			netEvent.ErrorCode = errorCode;
			netEvent.DisconnectReason = disconnectReason;
			netEvent.ConnectionRequest = connectionRequest;
			netEvent.DeliveryMethod = deliveryMethod;
			netEvent.ChannelNumber = channelNumber;
			netEvent.UserData = userData;
			if (flag || _manualMode)
			{
				ProcessEvent(netEvent);
				return;
			}
			lock (_eventLock)
			{
				if (_pendingEventTail == null)
				{
					_pendingEventHead = netEvent;
				}
				else
				{
					_pendingEventTail.Next = netEvent;
				}
				_pendingEventTail = netEvent;
			}
		}

		private void ProcessEvent(NetEvent evt)
		{
			bool isNull = evt.DataReader.IsNull;
			switch (evt.Type)
			{
			case NetEvent.EType.Connect:
				_netEventListener.OnPeerConnected(evt.Peer);
				break;
			case NetEvent.EType.Disconnect:
			{
				DisconnectInfo disconnectInfo = default(DisconnectInfo);
				disconnectInfo.Reason = evt.DisconnectReason;
				disconnectInfo.AdditionalData = evt.DataReader;
				disconnectInfo.SocketErrorCode = evt.ErrorCode;
				DisconnectInfo disconnectInfo2 = disconnectInfo;
				_netEventListener.OnPeerDisconnected(evt.Peer, disconnectInfo2);
				break;
			}
			case NetEvent.EType.Receive:
				_netEventListener.OnNetworkReceive(evt.Peer, evt.DataReader, evt.ChannelNumber, evt.DeliveryMethod);
				break;
			case NetEvent.EType.ReceiveUnconnected:
				_netEventListener.OnNetworkReceiveUnconnected(evt.RemoteEndPoint, evt.DataReader, UnconnectedMessageType.BasicMessage);
				break;
			case NetEvent.EType.Broadcast:
				_netEventListener.OnNetworkReceiveUnconnected(evt.RemoteEndPoint, evt.DataReader, UnconnectedMessageType.Broadcast);
				break;
			case NetEvent.EType.Error:
				_netEventListener.OnNetworkError(evt.RemoteEndPoint, evt.ErrorCode);
				break;
			case NetEvent.EType.ConnectionLatencyUpdated:
				_netEventListener.OnNetworkLatencyUpdate(evt.Peer, evt.Latency);
				break;
			case NetEvent.EType.ConnectionRequest:
				_netEventListener.OnConnectionRequest(evt.ConnectionRequest);
				break;
			case NetEvent.EType.MessageDelivered:
				_deliveryEventListener.OnMessageDelivered(evt.Peer, evt.UserData);
				break;
			case NetEvent.EType.PeerAddressChanged:
			{
				_peersLock.EnterUpgradeableReadLock();
				IPEndPoint iPEndPoint = null;
				if (ContainsPeer(evt.Peer))
				{
					_peersLock.EnterWriteLock();
					RemovePeerFromSet(evt.Peer);
					iPEndPoint = new IPEndPoint(evt.Peer.Address, evt.Peer.Port);
					evt.Peer.FinishEndPointChange(evt.RemoteEndPoint);
					AddPeerToSet(evt.Peer);
					_peersLock.ExitWriteLock();
				}
				_peersLock.ExitUpgradeableReadLock();
				if (iPEndPoint != null && _peerAddressChangedListener != null)
				{
					_peerAddressChangedListener.OnPeerAddressChanged(evt.Peer, iPEndPoint);
				}
				break;
			}
			}
			if (isNull)
			{
				RecycleEvent(evt);
			}
			else if (AutoRecycle)
			{
				evt.DataReader.RecycleInternal();
			}
		}

		internal void RecycleEvent(NetEvent evt)
		{
			evt.Peer = null;
			evt.ErrorCode = SocketError.Success;
			evt.RemoteEndPoint = null;
			evt.ConnectionRequest = null;
			lock (_eventLock)
			{
				evt.Next = _netEventPoolHead;
				_netEventPoolHead = evt;
			}
		}

		private void UpdateLogic()
		{
			List<NetPeer> list = new List<NetPeer>();
			Stopwatch stopwatch = new Stopwatch();
			stopwatch.Start();
			while (IsRunning)
			{
				try
				{
					float num = (float)((double)stopwatch.ElapsedTicks / (double)Stopwatch.Frequency * 1000.0);
					num = ((num <= 0f) ? 0.001f : num);
					stopwatch.Restart();
					for (NetPeer netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer)
					{
						if (netPeer.ConnectionState == ConnectionState.Disconnected && netPeer.TimeSinceLastPacket > (float)DisconnectTimeout)
						{
							list.Add(netPeer);
						}
						else
						{
							netPeer.Update(num);
						}
					}
					if (list.Count > 0)
					{
						_peersLock.EnterWriteLock();
						for (int i = 0; i < list.Count; i++)
						{
							RemovePeer(list[i], enableWriteLock: false);
						}
						_peersLock.ExitWriteLock();
						list.Clear();
					}
					ProcessNtpRequests(num);
					int num2 = UpdateTime - (int)stopwatch.ElapsedMilliseconds;
					if (num2 > 0)
					{
						_updateTriggerEvent.WaitOne(num2);
					}
				}
				catch (ThreadAbortException)
				{
					return;
				}
				catch (Exception ex2)
				{
					NetDebug.WriteError("[NM] LogicThread error: " + ex2);
				}
			}
			stopwatch.Stop();
		}

		[Conditional("DEBUG")]
		private void ProcessDelayedPackets()
		{
			if (!SimulateLatency)
			{
				return;
			}
			DateTime utcNow = DateTime.UtcNow;
			lock (_pingSimulationList)
			{
				for (int i = 0; i < _pingSimulationList.Count; i++)
				{
					IncomingData incomingData = _pingSimulationList[i];
					if (incomingData.TimeWhenGet <= utcNow)
					{
						HandleMessageReceived(incomingData.Data, incomingData.EndPoint);
						_pingSimulationList.RemoveAt(i);
						i--;
					}
				}
			}
		}

		private void ProcessNtpRequests(float elapsedMilliseconds)
		{
			List<IPEndPoint> list = null;
			foreach (KeyValuePair<IPEndPoint, NtpRequest> ntpRequest in _ntpRequests)
			{
				ntpRequest.Value.Send(_udpSocketv4, elapsedMilliseconds);
				if (ntpRequest.Value.NeedToKill)
				{
					if (list == null)
					{
						list = new List<IPEndPoint>();
					}
					list.Add(ntpRequest.Key);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (IPEndPoint item in list)
			{
				_ntpRequests.TryRemove(item, out var _);
			}
		}

		public void ManualUpdate(float elapsedMilliseconds)
		{
			if (!_manualMode)
			{
				return;
			}
			for (NetPeer netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer)
			{
				if (netPeer.ConnectionState == ConnectionState.Disconnected && netPeer.TimeSinceLastPacket > (float)DisconnectTimeout)
				{
					RemovePeer(netPeer, enableWriteLock: false);
				}
				else
				{
					netPeer.Update(elapsedMilliseconds);
				}
			}
			ProcessNtpRequests(elapsedMilliseconds);
		}

		internal NetPeer OnConnectionSolved(ConnectionRequest request, byte[] rejectData, int start, int length)
		{
			NetPeer actualValue = null;
			if (request.Result == ConnectionRequestResult.RejectForce)
			{
				if (rejectData != null && length > 0)
				{
					NetPacket netPacket = PoolGetWithProperty(PacketProperty.Disconnect, length);
					netPacket.ConnectionNumber = request.InternalPacket.ConnectionNumber;
					FastBitConverter.GetBytes(netPacket.RawData, 1, request.InternalPacket.ConnectionTime);
					if (netPacket.Size >= NetConstants.PossibleMtu[0])
					{
						NetDebug.WriteError("[Peer] Disconnect additional data size more than MTU!");
					}
					else
					{
						Buffer.BlockCopy(rejectData, start, netPacket.RawData, 9, length);
					}
					SendRawAndRecycle(netPacket, request.RemoteEndPoint);
				}
				lock (_requestsDict)
				{
					_requestsDict.Remove(request.RemoteEndPoint);
				}
			}
			else
			{
				lock (_requestsDict)
				{
					if (!TryGetPeer(request.RemoteEndPoint, out actualValue))
					{
						if (request.Result == ConnectionRequestResult.Reject)
						{
							actualValue = new NetPeer(this, request.RemoteEndPoint, GetNextPeerId());
							actualValue.Reject(request.InternalPacket, rejectData, start, length);
							AddPeer(actualValue);
						}
						else
						{
							actualValue = new NetPeer(this, request, GetNextPeerId());
							AddPeer(actualValue);
							CreateEvent(NetEvent.EType.Connect, actualValue, null, SocketError.Success, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0);
						}
					}
					_requestsDict.Remove(request.RemoteEndPoint);
				}
			}
			return actualValue;
		}

		private int GetNextPeerId()
		{
			if (!_peerIds.TryDequeue(out var result))
			{
				return _lastPeerId++;
			}
			return result;
		}

		private void ProcessConnectRequest(IPEndPoint remoteEndPoint, NetPeer netPeer, NetConnectRequestPacket connRequest)
		{
			if (netPeer != null)
			{
				ConnectRequestResult connectRequestResult = netPeer.ProcessConnectRequest(connRequest);
				switch (connectRequestResult)
				{
				default:
					return;
				case ConnectRequestResult.Reconnection:
					DisconnectPeerForce(netPeer, DisconnectReason.Reconnect, SocketError.Success, null);
					RemovePeer(netPeer, enableWriteLock: true);
					break;
				case ConnectRequestResult.NewConnection:
					RemovePeer(netPeer, enableWriteLock: true);
					break;
				case ConnectRequestResult.P2PLose:
					DisconnectPeerForce(netPeer, DisconnectReason.PeerToPeerConnection, SocketError.Success, null);
					RemovePeer(netPeer, enableWriteLock: true);
					break;
				}
				if (connectRequestResult != ConnectRequestResult.P2PLose)
				{
					connRequest.ConnectionNumber = (byte)((netPeer.ConnectionNum + 1) % 4);
				}
			}
			ConnectionRequest value;
			lock (_requestsDict)
			{
				if (_requestsDict.TryGetValue(remoteEndPoint, out value))
				{
					value.UpdateRequest(connRequest);
					return;
				}
				value = new ConnectionRequest(remoteEndPoint, connRequest, this);
				_requestsDict.Add(remoteEndPoint, value);
			}
			CreateEvent(NetEvent.EType.ConnectionRequest, null, null, SocketError.Success, 0, DisconnectReason.ConnectionFailed, value, DeliveryMethod.Unreliable, 0);
		}

		private void OnMessageReceived(NetPacket packet, IPEndPoint remoteEndPoint)
		{
			if (packet.Size == 0)
			{
				PoolRecycle(packet);
				return;
			}
			_dropPacket = false;
			if (!_dropPacket)
			{
				HandleMessageReceived(packet, remoteEndPoint);
			}
		}

		[Conditional("DEBUG")]
		private void HandleSimulateLatency(NetPacket packet, IPEndPoint remoteEndPoint)
		{
			if (!SimulateLatency)
			{
				return;
			}
			int num = _randomGenerator.Next(SimulationMinLatency, SimulationMaxLatency);
			if (num > 5)
			{
				lock (_pingSimulationList)
				{
					_pingSimulationList.Add(new IncomingData
					{
						Data = packet,
						EndPoint = remoteEndPoint,
						TimeWhenGet = DateTime.UtcNow.AddMilliseconds(num)
					});
				}
				_dropPacket = true;
			}
		}

		[Conditional("DEBUG")]
		private void HandleSimulatePacketLoss()
		{
			if (SimulatePacketLoss && _randomGenerator.NextDouble() * 100.0 < (double)SimulationPacketLossChance)
			{
				_dropPacket = true;
			}
		}

		private void HandleMessageReceived(NetPacket packet, IPEndPoint remoteEndPoint)
		{
			int size = packet.Size;
			if (EnableStatistics)
			{
				Statistics.IncrementPacketsReceived();
				Statistics.AddBytesReceived(size);
			}
			if (_ntpRequests.Count > 0 && _ntpRequests.TryGetValue(remoteEndPoint, out var _))
			{
				if (packet.Size >= 48)
				{
					byte[] array = new byte[packet.Size];
					Buffer.BlockCopy(packet.RawData, 0, array, 0, packet.Size);
					NtpPacket ntpPacket = NtpPacket.FromServerResponse(array, DateTime.UtcNow);
					try
					{
						ntpPacket.ValidateReply();
					}
					catch (InvalidOperationException)
					{
						ntpPacket = null;
					}
					if (ntpPacket != null)
					{
						_ntpRequests.TryRemove(remoteEndPoint, out var _);
						_ntpEventListener?.OnNtpResponse(ntpPacket);
					}
				}
				return;
			}
			if (_extraPacketLayer != null)
			{
				_extraPacketLayer.ProcessInboundPacket(ref remoteEndPoint, ref packet.RawData, ref packet.Size);
				if (packet.Size == 0)
				{
					return;
				}
			}
			if (!packet.Verify())
			{
				NetDebug.WriteError("[NM] DataReceived: bad!");
				PoolRecycle(packet);
				return;
			}
			switch (packet.Property)
			{
			case PacketProperty.ConnectRequest:
				if (NetConnectRequestPacket.GetProtocolId(packet) != 13)
				{
					SendRawAndRecycle(PoolGetWithProperty(PacketProperty.InvalidProtocol), remoteEndPoint);
					return;
				}
				break;
			case PacketProperty.Broadcast:
				if (BroadcastReceiveEnabled)
				{
					CreateEvent(NetEvent.EType.Broadcast, null, remoteEndPoint, SocketError.Success, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0, packet);
				}
				return;
			case PacketProperty.UnconnectedMessage:
				if (UnconnectedMessagesEnabled)
				{
					CreateEvent(NetEvent.EType.ReceiveUnconnected, null, remoteEndPoint, SocketError.Success, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0, packet);
				}
				return;
			case PacketProperty.NatMessage:
				if (NatPunchEnabled)
				{
					NatPunchModule.ProcessMessage(remoteEndPoint, packet);
				}
				return;
			}
			NetPeer actualValue = remoteEndPoint as NetPeer;
			bool flag = actualValue != null || TryGetPeer(remoteEndPoint, out actualValue);
			if (flag && EnableStatistics)
			{
				actualValue.Statistics.IncrementPacketsReceived();
				actualValue.Statistics.AddBytesReceived(size);
			}
			switch (packet.Property)
			{
			case PacketProperty.ConnectRequest:
			{
				NetConnectRequestPacket netConnectRequestPacket = NetConnectRequestPacket.FromData(packet);
				if (netConnectRequestPacket != null)
				{
					ProcessConnectRequest(remoteEndPoint, actualValue, netConnectRequestPacket);
				}
				break;
			}
			case PacketProperty.PeerNotFound:
				if (flag)
				{
					if (actualValue.ConnectionState == ConnectionState.Connected)
					{
						if (packet.Size == 1)
						{
							actualValue.ResetMtu();
							SendRaw(NetConnectAcceptPacket.MakeNetworkChanged(actualValue), remoteEndPoint);
						}
						else if (packet.Size == 2 && packet.RawData[1] == 1)
						{
							DisconnectPeerForce(actualValue, DisconnectReason.PeerNotFound, SocketError.Success, null);
						}
					}
				}
				else
				{
					if (packet.Size <= 1)
					{
						break;
					}
					bool flag2 = false;
					if (AllowPeerAddressChange)
					{
						NetConnectAcceptPacket netConnectAcceptPacket = NetConnectAcceptPacket.FromData(packet);
						if (netConnectAcceptPacket != null && netConnectAcceptPacket.PeerNetworkChanged && netConnectAcceptPacket.PeerId < _peersArray.Length)
						{
							_peersLock.EnterUpgradeableReadLock();
							NetPeer netPeer = _peersArray[netConnectAcceptPacket.PeerId];
							_peersLock.ExitUpgradeableReadLock();
							if (netPeer != null && netPeer.ConnectTime == netConnectAcceptPacket.ConnectionTime && netPeer.ConnectionNum == netConnectAcceptPacket.ConnectionNumber)
							{
								if (netPeer.ConnectionState == ConnectionState.Connected)
								{
									netPeer.InitiateEndPointChange();
									CreateEvent(NetEvent.EType.PeerAddressChanged, netPeer, remoteEndPoint, SocketError.Success, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0);
								}
								flag2 = true;
							}
						}
					}
					PoolRecycle(packet);
					if (!flag2)
					{
						NetPacket netPacket = PoolGetWithProperty(PacketProperty.PeerNotFound, 1);
						netPacket.RawData[1] = 1;
						SendRawAndRecycle(netPacket, remoteEndPoint);
					}
				}
				break;
			case PacketProperty.InvalidProtocol:
				if (flag && actualValue.ConnectionState == ConnectionState.Outgoing)
				{
					DisconnectPeerForce(actualValue, DisconnectReason.InvalidProtocol, SocketError.Success, null);
				}
				break;
			case PacketProperty.Disconnect:
				if (flag)
				{
					DisconnectResult disconnectResult = actualValue.ProcessDisconnect(packet);
					if (disconnectResult == DisconnectResult.None)
					{
						PoolRecycle(packet);
						break;
					}
					DisconnectPeerForce(actualValue, (disconnectResult == DisconnectResult.Disconnect) ? DisconnectReason.RemoteConnectionClose : DisconnectReason.ConnectionRejected, SocketError.Success, packet);
				}
				else
				{
					PoolRecycle(packet);
				}
				SendRawAndRecycle(PoolGetWithProperty(PacketProperty.ShutdownOk), remoteEndPoint);
				break;
			case PacketProperty.ConnectAccept:
				if (flag)
				{
					NetConnectAcceptPacket netConnectAcceptPacket2 = NetConnectAcceptPacket.FromData(packet);
					if (netConnectAcceptPacket2 != null && actualValue.ProcessConnectAccept(netConnectAcceptPacket2))
					{
						CreateEvent(NetEvent.EType.Connect, actualValue, null, SocketError.Success, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0);
					}
				}
				break;
			default:
				if (flag)
				{
					actualValue.ProcessPacket(packet);
				}
				else
				{
					SendRawAndRecycle(PoolGetWithProperty(PacketProperty.PeerNotFound), remoteEndPoint);
				}
				break;
			}
		}

		internal void CreateReceiveEvent(NetPacket packet, DeliveryMethod method, byte channelNumber, int headerSize, NetPeer fromPeer)
		{
			if (UnsyncedEvents || UnsyncedReceiveEvent || _manualMode)
			{
				NetEvent netEvent;
				lock (_eventLock)
				{
					netEvent = _netEventPoolHead;
					if (netEvent == null)
					{
						netEvent = new NetEvent(this);
					}
					else
					{
						_netEventPoolHead = netEvent.Next;
					}
				}
				netEvent.Next = null;
				netEvent.Type = NetEvent.EType.Receive;
				netEvent.DataReader.SetSource(packet, headerSize);
				netEvent.Peer = fromPeer;
				netEvent.DeliveryMethod = method;
				netEvent.ChannelNumber = channelNumber;
				ProcessEvent(netEvent);
				return;
			}
			lock (_eventLock)
			{
				NetEvent netEvent = _netEventPoolHead;
				if (netEvent == null)
				{
					netEvent = new NetEvent(this);
				}
				else
				{
					_netEventPoolHead = netEvent.Next;
				}
				netEvent.Next = null;
				netEvent.Type = NetEvent.EType.Receive;
				netEvent.DataReader.SetSource(packet, headerSize);
				netEvent.Peer = fromPeer;
				netEvent.DeliveryMethod = method;
				netEvent.ChannelNumber = channelNumber;
				if (_pendingEventTail == null)
				{
					_pendingEventHead = netEvent;
				}
				else
				{
					_pendingEventTail.Next = netEvent;
				}
				_pendingEventTail = netEvent;
			}
		}

		public void SendToAll(NetDataWriter writer, DeliveryMethod options)
		{
			SendToAll(writer.Data, 0, writer.Length, options);
		}

		public void SendToAll(byte[] data, DeliveryMethod options)
		{
			SendToAll(data, 0, data.Length, options);
		}

		public void SendToAll(byte[] data, int start, int length, DeliveryMethod options)
		{
			SendToAll(data, start, length, 0, options);
		}

		public void SendToAll(NetDataWriter writer, byte channelNumber, DeliveryMethod options)
		{
			SendToAll(writer.Data, 0, writer.Length, channelNumber, options);
		}

		public void SendToAll(byte[] data, byte channelNumber, DeliveryMethod options)
		{
			SendToAll(data, 0, data.Length, channelNumber, options);
		}

		public void SendToAll(byte[] data, int start, int length, byte channelNumber, DeliveryMethod options)
		{
			try
			{
				_peersLock.EnterReadLock();
				for (NetPeer netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer)
				{
					netPeer.Send(data, start, length, channelNumber, options);
				}
			}
			finally
			{
				_peersLock.ExitReadLock();
			}
		}

		public void SendToAll(NetDataWriter writer, DeliveryMethod options, NetPeer excludePeer)
		{
			SendToAll(writer.Data, 0, writer.Length, 0, options, excludePeer);
		}

		public void SendToAll(byte[] data, DeliveryMethod options, NetPeer excludePeer)
		{
			SendToAll(data, 0, data.Length, 0, options, excludePeer);
		}

		public void SendToAll(byte[] data, int start, int length, DeliveryMethod options, NetPeer excludePeer)
		{
			SendToAll(data, start, length, 0, options, excludePeer);
		}

		public void SendToAll(NetDataWriter writer, byte channelNumber, DeliveryMethod options, NetPeer excludePeer)
		{
			SendToAll(writer.Data, 0, writer.Length, channelNumber, options, excludePeer);
		}

		public void SendToAll(byte[] data, byte channelNumber, DeliveryMethod options, NetPeer excludePeer)
		{
			SendToAll(data, 0, data.Length, channelNumber, options, excludePeer);
		}

		public void SendToAll(byte[] data, int start, int length, byte channelNumber, DeliveryMethod options, NetPeer excludePeer)
		{
			try
			{
				_peersLock.EnterReadLock();
				for (NetPeer netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer)
				{
					if (netPeer != excludePeer)
					{
						netPeer.Send(data, start, length, channelNumber, options);
					}
				}
			}
			finally
			{
				_peersLock.ExitReadLock();
			}
		}

		public void SendToAll(ReadOnlySpan<byte> data, DeliveryMethod options)
		{
			SendToAll(data, 0, options, null);
		}

		public void SendToAll(ReadOnlySpan<byte> data, DeliveryMethod options, NetPeer excludePeer)
		{
			SendToAll(data, 0, options, excludePeer);
		}

		public void SendToAll(ReadOnlySpan<byte> data, byte channelNumber, DeliveryMethod options, NetPeer excludePeer)
		{
			try
			{
				_peersLock.EnterReadLock();
				for (NetPeer netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer)
				{
					if (netPeer != excludePeer)
					{
						netPeer.Send(data, channelNumber, options);
					}
				}
			}
			finally
			{
				_peersLock.ExitReadLock();
			}
		}

		public bool SendUnconnectedMessage(ReadOnlySpan<byte> message, IPEndPoint remoteEndPoint)
		{
			int headerSize = NetPacket.GetHeaderSize(PacketProperty.UnconnectedMessage);
			NetPacket netPacket = PoolGetPacket(message.Length + headerSize);
			netPacket.Property = PacketProperty.UnconnectedMessage;
			message.CopyTo(new Span<byte>(netPacket.RawData, headerSize, message.Length));
			return SendRawAndRecycle(netPacket, remoteEndPoint) > 0;
		}

		public bool Start()
		{
			return Start(0);
		}

		public bool Start(IPAddress addressIPv4, IPAddress addressIPv6, int port)
		{
			return Start(addressIPv4, addressIPv6, port, manualMode: false);
		}

		public bool Start(string addressIPv4, string addressIPv6, int port)
		{
			IPAddress addressIPv7 = NetUtils.ResolveAddress(addressIPv4);
			IPAddress addressIPv8 = NetUtils.ResolveAddress(addressIPv6);
			return Start(addressIPv7, addressIPv8, port);
		}

		public bool Start(int port)
		{
			return Start(IPAddress.Any, IPAddress.IPv6Any, port);
		}

		public bool StartInManualMode(IPAddress addressIPv4, IPAddress addressIPv6, int port)
		{
			return Start(addressIPv4, addressIPv6, port, manualMode: true);
		}

		public bool StartInManualMode(string addressIPv4, string addressIPv6, int port)
		{
			IPAddress addressIPv7 = NetUtils.ResolveAddress(addressIPv4);
			IPAddress addressIPv8 = NetUtils.ResolveAddress(addressIPv6);
			return StartInManualMode(addressIPv7, addressIPv8, port);
		}

		public bool StartInManualMode(int port)
		{
			return StartInManualMode(IPAddress.Any, IPAddress.IPv6Any, port);
		}

		public bool SendUnconnectedMessage(byte[] message, IPEndPoint remoteEndPoint)
		{
			return SendUnconnectedMessage(message, 0, message.Length, remoteEndPoint);
		}

		public bool SendUnconnectedMessage(NetDataWriter writer, string address, int port)
		{
			IPEndPoint remoteEndPoint = NetUtils.MakeEndPoint(address, port);
			return SendUnconnectedMessage(writer.Data, 0, writer.Length, remoteEndPoint);
		}

		public bool SendUnconnectedMessage(NetDataWriter writer, IPEndPoint remoteEndPoint)
		{
			return SendUnconnectedMessage(writer.Data, 0, writer.Length, remoteEndPoint);
		}

		public bool SendUnconnectedMessage(byte[] message, int start, int length, IPEndPoint remoteEndPoint)
		{
			NetPacket packet = PoolGetWithData(PacketProperty.UnconnectedMessage, message, start, length);
			return SendRawAndRecycle(packet, remoteEndPoint) > 0;
		}

		public void TriggerUpdate()
		{
			_updateTriggerEvent.Set();
		}

		public void PollEvents(int maxProcessedEvents = 0)
		{
			if (_manualMode)
			{
				if (_udpSocketv4 != null)
				{
					ManualReceive(_udpSocketv4, _bufferEndPointv4, maxProcessedEvents);
				}
				if (_udpSocketv6 != null && _udpSocketv6 != _udpSocketv4)
				{
					ManualReceive(_udpSocketv6, _bufferEndPointv6, maxProcessedEvents);
				}
			}
			else
			{
				if (UnsyncedEvents)
				{
					return;
				}
				NetEvent netEvent;
				lock (_eventLock)
				{
					netEvent = _pendingEventHead;
					_pendingEventHead = null;
					_pendingEventTail = null;
				}
				int num = 0;
				while (netEvent != null)
				{
					NetEvent next = netEvent.Next;
					ProcessEvent(netEvent);
					netEvent = next;
					num++;
					if (num == maxProcessedEvents)
					{
						break;
					}
				}
			}
		}

		public NetPeer Connect(string address, int port, string key)
		{
			return Connect(address, port, NetDataWriter.FromString(key));
		}

		public NetPeer Connect(string address, int port, NetDataWriter connectionData)
		{
			IPEndPoint target;
			try
			{
				target = NetUtils.MakeEndPoint(address, port);
			}
			catch
			{
				CreateEvent(NetEvent.EType.Disconnect, null, null, SocketError.Success, 0, DisconnectReason.UnknownHost, null, DeliveryMethod.Unreliable, 0);
				return null;
			}
			return Connect(target, connectionData);
		}

		public NetPeer Connect(IPEndPoint target, string key)
		{
			return Connect(target, NetDataWriter.FromString(key));
		}

		public NetPeer Connect(IPEndPoint target, NetDataWriter connectionData)
		{
			if (!IsRunning)
			{
				throw new InvalidOperationException("Client is not running");
			}
			lock (_requestsDict)
			{
				if (_requestsDict.ContainsKey(target))
				{
					return null;
				}
				byte connectNum = 0;
				if (TryGetPeer(target, out var actualValue))
				{
					ConnectionState connectionState = actualValue.ConnectionState;
					if (connectionState == ConnectionState.Outgoing || connectionState == ConnectionState.Connected)
					{
						return actualValue;
					}
					connectNum = (byte)((actualValue.ConnectionNum + 1) % 4);
					RemovePeer(actualValue, enableWriteLock: true);
				}
				actualValue = new NetPeer(this, target, GetNextPeerId(), connectNum, connectionData);
				AddPeer(actualValue);
				return actualValue;
			}
		}

		public void Stop()
		{
			Stop(sendDisconnectMessages: true);
		}

		public void Stop(bool sendDisconnectMessages)
		{
			if (IsRunning)
			{
				for (NetPeer netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer)
				{
					netPeer.Shutdown(null, 0, 0, !sendDisconnectMessages);
				}
				CloseSocket();
				_updateTriggerEvent.Set();
				if (!_manualMode)
				{
					_logicThread.Join();
					_logicThread = null;
				}
				ClearPeerSet();
				_peerIds = new ConcurrentQueue<int>();
				_lastPeerId = 0;
				_connectedPeersCount = 0L;
				_pendingEventHead = null;
				_pendingEventTail = null;
			}
		}

		[Conditional("DEBUG")]
		private void ClearPingSimulationList()
		{
			lock (_pingSimulationList)
			{
				_pingSimulationList.Clear();
			}
		}

		public int GetPeersCount(ConnectionState peerState)
		{
			int num = 0;
			_peersLock.EnterReadLock();
			for (NetPeer netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer)
			{
				if ((netPeer.ConnectionState & peerState) != 0)
				{
					num++;
				}
			}
			_peersLock.ExitReadLock();
			return num;
		}

		public void GetPeersNonAlloc(List<NetPeer> peers, ConnectionState peerState)
		{
			peers.Clear();
			_peersLock.EnterReadLock();
			for (NetPeer netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer)
			{
				if ((netPeer.ConnectionState & peerState) != 0)
				{
					peers.Add(netPeer);
				}
			}
			_peersLock.ExitReadLock();
		}

		public void DisconnectAll()
		{
			DisconnectAll(null, 0, 0);
		}

		public void DisconnectAll(byte[] data, int start, int count)
		{
			_peersLock.EnterReadLock();
			for (NetPeer netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer)
			{
				DisconnectPeer(netPeer, DisconnectReason.DisconnectPeerCalled, SocketError.Success, force: false, data, start, count, null);
			}
			_peersLock.ExitReadLock();
		}

		public void DisconnectPeerForce(NetPeer peer)
		{
			DisconnectPeerForce(peer, DisconnectReason.DisconnectPeerCalled, SocketError.Success, null);
		}

		public void DisconnectPeer(NetPeer peer)
		{
			DisconnectPeer(peer, null, 0, 0);
		}

		public void DisconnectPeer(NetPeer peer, byte[] data)
		{
			DisconnectPeer(peer, data, 0, data.Length);
		}

		public void DisconnectPeer(NetPeer peer, NetDataWriter writer)
		{
			DisconnectPeer(peer, writer.Data, 0, writer.Length);
		}

		public void DisconnectPeer(NetPeer peer, byte[] data, int start, int count)
		{
			DisconnectPeer(peer, DisconnectReason.DisconnectPeerCalled, SocketError.Success, force: false, data, start, count, null);
		}

		public void CreateNtpRequest(IPEndPoint endPoint)
		{
			_ntpRequests.TryAdd(endPoint, new NtpRequest(endPoint));
		}

		public void CreateNtpRequest(string ntpServerAddress, int port)
		{
			IPEndPoint iPEndPoint = NetUtils.MakeEndPoint(ntpServerAddress, port);
			_ntpRequests.TryAdd(iPEndPoint, new NtpRequest(iPEndPoint));
		}

		public void CreateNtpRequest(string ntpServerAddress)
		{
			IPEndPoint iPEndPoint = NetUtils.MakeEndPoint(ntpServerAddress, 123);
			_ntpRequests.TryAdd(iPEndPoint, new NtpRequest(iPEndPoint));
		}

		public NetPeerEnumerator GetEnumerator()
		{
			return new NetPeerEnumerator(_headPeer);
		}

		IEnumerator<NetPeer> IEnumerable<NetPeer>.GetEnumerator()
		{
			return new NetPeerEnumerator(_headPeer);
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return new NetPeerEnumerator(_headPeer);
		}

		private static int HashSetGetPrime(int min)
		{
			int[] primes = Primes;
			foreach (int num in primes)
			{
				if (num >= min)
				{
					return num;
				}
			}
			for (int j = min | 1; j < int.MaxValue; j += 2)
			{
				if (IsPrime(j) && (j - 1) % 101 != 0)
				{
					return j;
				}
			}
			return min;
			static bool IsPrime(int candidate)
			{
				if (((uint)candidate & (true ? 1u : 0u)) != 0)
				{
					int num2 = (int)Math.Sqrt(candidate);
					for (int k = 3; k <= num2; k += 2)
					{
						if (candidate % k == 0)
						{
							return false;
						}
					}
					return true;
				}
				return candidate == 2;
			}
		}

		private void ClearPeerSet()
		{
			_peersLock.EnterWriteLock();
			_headPeer = null;
			if (_lastIndex > 0)
			{
				Array.Clear(_slots, 0, _lastIndex);
				Array.Clear(_buckets, 0, _buckets.Length);
				_lastIndex = 0;
				_count = 0;
				_freeList = -1;
			}
			_peersArray = new NetPeer[32];
			_peersLock.ExitWriteLock();
		}

		private bool ContainsPeer(NetPeer item)
		{
			if (item == null)
			{
				NetDebug.WriteError($"Contains peer null: {item}");
				return false;
			}
			if (_buckets != null)
			{
				int num = item.GetHashCode() & 0x7FFFFFFF;
				for (int num2 = _buckets[num % _buckets.Length] - 1; num2 >= 0; num2 = _slots[num2].Next)
				{
					if (_slots[num2].HashCode == num && _slots[num2].Value.Equals(item))
					{
						return true;
					}
				}
			}
			return false;
		}

		public NetPeer GetPeerById(int id)
		{
			if (id < 0 || id >= _peersArray.Length)
			{
				return null;
			}
			return _peersArray[id];
		}

		public bool TryGetPeerById(int id, out NetPeer peer)
		{
			peer = GetPeerById(id);
			return peer != null;
		}

		private void AddPeer(NetPeer peer)
		{
			if (peer == null)
			{
				NetDebug.WriteError($"Add peer null: {peer}");
				return;
			}
			_peersLock.EnterWriteLock();
			if (_headPeer != null)
			{
				peer.NextPeer = _headPeer;
				_headPeer.PrevPeer = peer;
			}
			_headPeer = peer;
			AddPeerToSet(peer);
			if (peer.Id >= _peersArray.Length)
			{
				int num = _peersArray.Length * 2;
				while (peer.Id >= num)
				{
					num *= 2;
				}
				Array.Resize(ref _peersArray, num);
			}
			_peersArray[peer.Id] = peer;
			_peersLock.ExitWriteLock();
		}

		private void RemovePeer(NetPeer peer, bool enableWriteLock)
		{
			if (enableWriteLock)
			{
				_peersLock.EnterWriteLock();
			}
			if (!RemovePeerFromSet(peer))
			{
				if (enableWriteLock)
				{
					_peersLock.ExitWriteLock();
				}
				return;
			}
			if (peer == _headPeer)
			{
				_headPeer = peer.NextPeer;
			}
			if (peer.PrevPeer != null)
			{
				peer.PrevPeer.NextPeer = peer.NextPeer;
			}
			if (peer.NextPeer != null)
			{
				peer.NextPeer.PrevPeer = peer.PrevPeer;
			}
			peer.PrevPeer = null;
			_peersArray[peer.Id] = null;
			_peerIds.Enqueue(peer.Id);
			if (enableWriteLock)
			{
				_peersLock.ExitWriteLock();
			}
		}

		private bool RemovePeerFromSet(NetPeer peer)
		{
			if (_buckets == null || peer == null)
			{
				return false;
			}
			int num = peer.GetHashCode() & 0x7FFFFFFF;
			int num2 = num % _buckets.Length;
			int num3 = -1;
			for (int num4 = _buckets[num2] - 1; num4 >= 0; num4 = _slots[num4].Next)
			{
				if (_slots[num4].HashCode == num && _slots[num4].Value.Equals(peer))
				{
					if (num3 < 0)
					{
						_buckets[num2] = _slots[num4].Next + 1;
					}
					else
					{
						_slots[num3].Next = _slots[num4].Next;
					}
					_slots[num4].HashCode = -1;
					_slots[num4].Value = null;
					_slots[num4].Next = _freeList;
					_count--;
					if (_count == 0)
					{
						_lastIndex = 0;
						_freeList = -1;
					}
					else
					{
						_freeList = num4;
					}
					return true;
				}
				num3 = num4;
			}
			return false;
		}

		private bool TryGetPeer(IPEndPoint endPoint, out NetPeer actualValue)
		{
			if (_buckets != null)
			{
				int num = endPoint.GetHashCode() & 0x7FFFFFFF;
				_peersLock.EnterReadLock();
				for (int num2 = _buckets[num % _buckets.Length] - 1; num2 >= 0; num2 = _slots[num2].Next)
				{
					if (_slots[num2].HashCode == num && _slots[num2].Value.Equals(endPoint))
					{
						actualValue = _slots[num2].Value;
						_peersLock.ExitReadLock();
						return true;
					}
				}
				_peersLock.ExitReadLock();
			}
			actualValue = null;
			return false;
		}

		private bool TryGetPeer(SocketAddress saddr, out NetPeer actualValue)
		{
			if (_buckets != null)
			{
				int num = saddr.GetHashCode() & 0x7FFFFFFF;
				_peersLock.EnterReadLock();
				for (int num2 = _buckets[num % _buckets.Length] - 1; num2 >= 0; num2 = _slots[num2].Next)
				{
					if (_slots[num2].HashCode == num && _slots[num2].Value.Serialize().Equals(saddr))
					{
						actualValue = _slots[num2].Value;
						_peersLock.ExitReadLock();
						return true;
					}
				}
				_peersLock.ExitReadLock();
			}
			actualValue = null;
			return false;
		}

		private bool AddPeerToSet(NetPeer value)
		{
			if (_buckets == null)
			{
				int num = HashSetGetPrime(0);
				_buckets = new int[num];
				_slots = new Slot[num];
			}
			int num2 = value.GetHashCode() & 0x7FFFFFFF;
			int num3 = num2 % _buckets.Length;
			for (int num4 = _buckets[num2 % _buckets.Length] - 1; num4 >= 0; num4 = _slots[num4].Next)
			{
				if (_slots[num4].HashCode == num2 && _slots[num4].Value.Equals(value))
				{
					return false;
				}
			}
			int num5;
			if (_freeList >= 0)
			{
				num5 = _freeList;
				_freeList = _slots[num5].Next;
			}
			else
			{
				if (_lastIndex == _slots.Length)
				{
					int num6 = 2 * _count;
					num6 = (((uint)num6 > 2147483587u && 2147483587 > _count) ? 2147483587 : HashSetGetPrime(num6));
					Slot[] array = new Slot[num6];
					Array.Copy(_slots, 0, array, 0, _lastIndex);
					_buckets = new int[num6];
					for (int i = 0; i < _lastIndex; i++)
					{
						int num7 = array[i].HashCode % num6;
						array[i].Next = _buckets[num7] - 1;
						_buckets[num7] = i + 1;
					}
					_slots = array;
					num3 = num2 % _buckets.Length;
				}
				num5 = _lastIndex;
				_lastIndex++;
			}
			_slots[num5].HashCode = num2;
			_slots[num5].Value = value;
			_slots[num5].Next = _buckets[num3] - 1;
			_buckets[num3] = num5 + 1;
			_count++;
			return true;
		}

		private NetPacket PoolGetWithData(PacketProperty property, byte[] data, int start, int length)
		{
			int headerSize = NetPacket.GetHeaderSize(property);
			NetPacket netPacket = PoolGetPacket(length + headerSize);
			netPacket.Property = property;
			Buffer.BlockCopy(data, start, netPacket.RawData, headerSize, length);
			return netPacket;
		}

		private NetPacket PoolGetWithProperty(PacketProperty property, int size)
		{
			NetPacket netPacket = PoolGetPacket(size + NetPacket.GetHeaderSize(property));
			netPacket.Property = property;
			return netPacket;
		}

		private NetPacket PoolGetWithProperty(PacketProperty property)
		{
			NetPacket netPacket = PoolGetPacket(NetPacket.GetHeaderSize(property));
			netPacket.Property = property;
			return netPacket;
		}

		internal NetPacket PoolGetPacket(int size)
		{
			if (size > NetConstants.MaxPacketSize)
			{
				return new NetPacket(size);
			}
			NetPacket poolHead;
			lock (_poolLock)
			{
				poolHead = _poolHead;
				if (poolHead == null)
				{
					return new NetPacket(size);
				}
				_poolHead = _poolHead.Next;
				_poolCount--;
			}
			poolHead.Size = size;
			if (poolHead.RawData.Length < size)
			{
				poolHead.RawData = new byte[size];
			}
			return poolHead;
		}

		internal void PoolRecycle(NetPacket packet)
		{
			if (packet.RawData.Length > NetConstants.MaxPacketSize || _poolCount >= PacketPoolSize)
			{
				return;
			}
			packet.RawData[0] = 0;
			lock (_poolLock)
			{
				packet.Next = _poolHead;
				_poolHead = packet;
				_poolCount++;
			}
		}

		static NetManager()
		{
			Primes = new int[72]
			{
				3, 7, 11, 17, 23, 29, 37, 47, 59, 71,
				89, 107, 131, 163, 197, 239, 293, 353, 431, 521,
				631, 761, 919, 1103, 1327, 1597, 1931, 2333, 2801, 3371,
				4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591, 17519, 21023,
				25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363,
				156437, 187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403,
				968897, 1162687, 1395263, 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559,
				5999471, 7199369
			};
			MulticastAddressV6 = IPAddress.Parse("ff02::1");
			IPv6Support = Socket.OSSupportsIPv6;
		}

		private bool ProcessError(SocketException ex)
		{
			switch (ex.SocketErrorCode)
			{
			case SocketError.NotConnected:
				NotConnected = true;
				return true;
			case SocketError.OperationAborted:
			case SocketError.Interrupted:
			case SocketError.NotSocket:
				return true;
			default:
				NetDebug.WriteError($"[R]Error code: {ex.SocketErrorCode} - {ex}");
				CreateEvent(NetEvent.EType.Error, null, null, ex.SocketErrorCode, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0);
				break;
			case SocketError.WouldBlock:
			case SocketError.MessageSize:
			case SocketError.NetworkReset:
			case SocketError.ConnectionReset:
			case SocketError.TimedOut:
				break;
			}
			return false;
		}

		private void ManualReceive(Socket socket, EndPoint bufferEndPoint, int maxReceive)
		{
			try
			{
				int num = 0;
				while (socket.Available > 0)
				{
					ReceiveFrom(socket, ref bufferEndPoint);
					num++;
					if (num == maxReceive)
					{
						break;
					}
				}
			}
			catch (SocketException ex)
			{
				ProcessError(ex);
			}
			catch (ObjectDisposedException)
			{
			}
			catch (Exception ex3)
			{
				NetDebug.WriteError("[NM] SocketReceiveThread error: " + ex3);
			}
		}

		private void NativeReceiveLogic()
		{
			IntPtr handle = _udpSocketv4.Handle;
			IntPtr s2 = _udpSocketv6?.Handle ?? IntPtr.Zero;
			byte[] address2 = new byte[16];
			byte[] address3 = new byte[28];
			IPEndPoint tempEndPoint = new IPEndPoint(IPAddress.Any, 0);
			List<Socket> list = new List<Socket>(2);
			Socket udpSocketv = _udpSocketv4;
			Socket udpSocketv2 = _udpSocketv6;
			NetPacket packet = PoolGetPacket(NetConstants.MaxPacketSize);
			while (IsRunning)
			{
				try
				{
					if (udpSocketv2 == null)
					{
						if (!NativeReceiveFrom(handle, address2))
						{
							break;
						}
						continue;
					}
					bool flag = false;
					if (udpSocketv.Available != 0 || list.Contains(udpSocketv))
					{
						if (!NativeReceiveFrom(handle, address2))
						{
							break;
						}
						flag = true;
					}
					if (udpSocketv2.Available != 0 || list.Contains(udpSocketv2))
					{
						if (!NativeReceiveFrom(s2, address3))
						{
							break;
						}
						flag = true;
					}
					list.Clear();
					if (!flag)
					{
						list.Add(udpSocketv);
						list.Add(udpSocketv2);
						Socket.Select(list, null, null, 500000);
					}
				}
				catch (SocketException ex)
				{
					if (ProcessError(ex))
					{
						break;
					}
				}
				catch (ObjectDisposedException)
				{
					break;
				}
				catch (ThreadAbortException)
				{
					break;
				}
				catch (Exception ex4)
				{
					NetDebug.WriteError("[NM] SocketReceiveThread error: " + ex4);
				}
			}
			bool NativeReceiveFrom(IntPtr s, byte[] address)
			{
				int socketAddressSize = address.Length;
				packet.Size = NativeSocket.RecvFrom(s, packet.RawData, NetConstants.MaxPacketSize, address, ref socketAddressSize);
				if (packet.Size == 0)
				{
					return true;
				}
				if (packet.Size == -1)
				{
					return !ProcessError(new SocketException((int)NativeSocket.GetSocketError()));
				}
				short num = (short)((address[1] << 8) | address[0]);
				tempEndPoint.Port = (ushort)((address[2] << 8) | address[3]);
				if ((NativeSocket.UnixMode && num == 10) || (!NativeSocket.UnixMode && num == 23))
				{
					uint num2 = (uint)((address[27] << 24) + (address[26] << 16) + (address[25] << 8) + address[24]);
					tempEndPoint.Address = new IPAddress(new ReadOnlySpan<byte>(address, 8, 16), num2);
				}
				else
				{
					long newAddress = (uint)((address[4] & 0xFF) | ((address[5] << 8) & 0xFF00) | ((address[6] << 16) & 0xFF0000) | (address[7] << 24));
					tempEndPoint.Address = new IPAddress(newAddress);
				}
				if (TryGetPeer(tempEndPoint, out var actualValue))
				{
					OnMessageReceived(packet, actualValue);
				}
				else
				{
					OnMessageReceived(packet, tempEndPoint);
					tempEndPoint = new IPEndPoint(IPAddress.Any, 0);
				}
				packet = PoolGetPacket(NetConstants.MaxPacketSize);
				return true;
			}
		}

		private void ReceiveFrom(Socket s, ref EndPoint bufferEndPoint)
		{
			NetPacket netPacket = PoolGetPacket(NetConstants.MaxPacketSize);
			netPacket.Size = s.ReceiveFrom(netPacket.RawData, 0, NetConstants.MaxPacketSize, SocketFlags.None, ref bufferEndPoint);
			OnMessageReceived(netPacket, (IPEndPoint)bufferEndPoint);
		}

		private void ReceiveLogic()
		{
			EndPoint bufferEndPoint = new IPEndPoint(IPAddress.Any, 0);
			EndPoint bufferEndPoint2 = new IPEndPoint(IPAddress.IPv6Any, 0);
			List<Socket> list = new List<Socket>(2);
			Socket udpSocketv = _udpSocketv4;
			Socket udpSocketv2 = _udpSocketv6;
			while (IsRunning)
			{
				try
				{
					if (udpSocketv2 == null)
					{
						if (udpSocketv.Available != 0 || udpSocketv.Poll(500000, SelectMode.SelectRead))
						{
							ReceiveFrom(udpSocketv, ref bufferEndPoint);
						}
						continue;
					}
					bool flag = false;
					if (udpSocketv.Available != 0 || list.Contains(udpSocketv))
					{
						ReceiveFrom(udpSocketv, ref bufferEndPoint);
						flag = true;
					}
					if (udpSocketv2.Available != 0 || list.Contains(udpSocketv2))
					{
						ReceiveFrom(udpSocketv2, ref bufferEndPoint2);
						flag = true;
					}
					list.Clear();
					if (!flag)
					{
						list.Add(udpSocketv);
						list.Add(udpSocketv2);
						Socket.Select(list, null, null, 500000);
					}
				}
				catch (SocketException ex)
				{
					if (ProcessError(ex))
					{
						break;
					}
				}
				catch (ObjectDisposedException)
				{
					break;
				}
				catch (ThreadAbortException)
				{
					break;
				}
				catch (Exception ex4)
				{
					NetDebug.WriteError("[NM] SocketReceiveThread error: " + ex4);
				}
			}
		}

		public bool Start(IPAddress addressIPv4, IPAddress addressIPv6, int port, bool manualMode)
		{
			if (IsRunning && !NotConnected)
			{
				return false;
			}
			NotConnected = false;
			_manualMode = manualMode;
			UseNativeSockets = UseNativeSockets && NativeSocket.IsSupported;
			_udpSocketv4 = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
			if (!BindSocket(_udpSocketv4, new IPEndPoint(addressIPv4, port)))
			{
				return false;
			}
			LocalPort = ((IPEndPoint)_udpSocketv4.LocalEndPoint).Port;
			IsRunning = true;
			if (_manualMode)
			{
				_bufferEndPointv4 = new IPEndPoint(IPAddress.Any, 0);
			}
			if (IPv6Support && IPv6Enabled)
			{
				_udpSocketv6 = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);
				if (BindSocket(_udpSocketv6, new IPEndPoint(addressIPv6, LocalPort)))
				{
					if (_manualMode)
					{
						_bufferEndPointv6 = new IPEndPoint(IPAddress.IPv6Any, 0);
					}
				}
				else
				{
					_udpSocketv6 = null;
				}
			}
			if (!manualMode)
			{
				ThreadStart start = ReceiveLogic;
				if (UseNativeSockets)
				{
					start = NativeReceiveLogic;
				}
				_receiveThread = new Thread(start)
				{
					Name = $"ReceiveThread({LocalPort})",
					IsBackground = true
				};
				_receiveThread.Start();
				if (_logicThread == null)
				{
					_logicThread = new Thread(UpdateLogic)
					{
						Name = "LogicThread",
						IsBackground = true
					};
					_logicThread.Start();
				}
			}
			return true;
		}

		private bool BindSocket(Socket socket, IPEndPoint ep)
		{
			socket.ReceiveTimeout = 500;
			socket.SendTimeout = 500;
			socket.ReceiveBufferSize = 1048576;
			socket.SendBufferSize = 1048576;
			socket.Blocking = true;
			if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
			{
				try
				{
					socket.IOControl(-1744830452, new byte[1], null);
				}
				catch
				{
				}
			}
			try
			{
				socket.ExclusiveAddressUse = !ReuseAddress;
				socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, ReuseAddress);
				socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontRoute, DontRoute);
			}
			catch
			{
			}
			if (ep.AddressFamily == AddressFamily.InterNetwork)
			{
				Ttl = 255;
				try
				{
					socket.EnableBroadcast = true;
				}
				catch (SocketException ex)
				{
					NetDebug.WriteError($"[B]Broadcast error: {ex.SocketErrorCode}");
				}
				if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
				{
					try
					{
						socket.DontFragment = true;
					}
					catch (SocketException ex2)
					{
						NetDebug.WriteError($"[B]DontFragment error: {ex2.SocketErrorCode}");
					}
				}
			}
			try
			{
				socket.Bind(ep);
				if (ep.AddressFamily == AddressFamily.InterNetworkV6)
				{
					try
					{
						socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.AddMembership, new IPv6MulticastOption(MulticastAddressV6));
					}
					catch (Exception)
					{
					}
				}
			}
			catch (SocketException ex4)
			{
				switch (ex4.SocketErrorCode)
				{
				case SocketError.AddressAlreadyInUse:
					if (socket.AddressFamily == AddressFamily.InterNetworkV6)
					{
						try
						{
							socket.DualMode = false;
							socket.Bind(ep);
						}
						catch (SocketException ex5)
						{
							NetDebug.WriteError($"[B]Bind exception: {ex5}, errorCode: {ex5.SocketErrorCode}");
							return false;
						}
						return true;
					}
					break;
				case SocketError.AddressFamilyNotSupported:
					return true;
				}
				NetDebug.WriteError($"[B]Bind exception: {ex4}, errorCode: {ex4.SocketErrorCode}");
				return false;
			}
			return true;
		}

		internal int SendRawAndRecycle(NetPacket packet, IPEndPoint remoteEndPoint)
		{
			int result = SendRaw(packet.RawData, 0, packet.Size, remoteEndPoint);
			PoolRecycle(packet);
			return result;
		}

		internal int SendRaw(NetPacket packet, IPEndPoint remoteEndPoint)
		{
			return SendRaw(packet.RawData, 0, packet.Size, remoteEndPoint);
		}

		internal unsafe int SendRaw(byte[] message, int start, int length, IPEndPoint remoteEndPoint)
		{
			if (!IsRunning)
			{
				return 0;
			}
			NetPacket netPacket = null;
			if (_extraPacketLayer != null)
			{
				netPacket = PoolGetPacket(length + _extraPacketLayer.ExtraPacketSizeForLayer);
				Buffer.BlockCopy(message, start, netPacket.RawData, 0, length);
				start = 0;
				_extraPacketLayer.ProcessOutBoundPacket(ref remoteEndPoint, ref netPacket.RawData, ref start, ref length);
				message = netPacket.RawData;
			}
			Socket socket = _udpSocketv4;
			if (remoteEndPoint.AddressFamily == AddressFamily.InterNetworkV6 && IPv6Support)
			{
				socket = _udpSocketv6;
				if (socket == null)
				{
					return 0;
				}
			}
			int num;
			try
			{
				if (UseNativeSockets && remoteEndPoint is NetPeer netPeer)
				{
					fixed (byte* pinnedBuffer = &message[start])
					{
						num = NativeSocket.SendTo(socket.Handle, pinnedBuffer, length, netPeer.NativeAddress, netPeer.NativeAddress.Length);
					}
					if (num == -1)
					{
						throw NativeSocket.GetSocketException();
					}
				}
				else
				{
					num = socket.SendTo(message, start, length, SocketFlags.None, remoteEndPoint);
				}
			}
			catch (SocketException ex)
			{
				switch (ex.SocketErrorCode)
				{
				case SocketError.Interrupted:
				case SocketError.NoBufferSpaceAvailable:
					return 0;
				case SocketError.MessageSize:
					return 0;
				case SocketError.NetworkUnreachable:
				case SocketError.HostUnreachable:
					if (DisconnectOnUnreachable && remoteEndPoint is NetPeer peer)
					{
						DisconnectPeerForce(peer, (ex.SocketErrorCode == SocketError.HostUnreachable) ? DisconnectReason.HostUnreachable : DisconnectReason.NetworkUnreachable, ex.SocketErrorCode, null);
					}
					CreateEvent(NetEvent.EType.Error, null, remoteEndPoint, ex.SocketErrorCode, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0);
					return -1;
				case SocketError.Shutdown:
					CreateEvent(NetEvent.EType.Error, null, remoteEndPoint, ex.SocketErrorCode, 0, DisconnectReason.ConnectionFailed, null, DeliveryMethod.Unreliable, 0);
					return -1;
				default:
					NetDebug.WriteError($"[S] {ex}");
					return -1;
				}
			}
			catch (Exception value)
			{
				NetDebug.WriteError($"[S] {value}");
				return 0;
			}
			finally
			{
				if (netPacket != null)
				{
					PoolRecycle(netPacket);
				}
			}
			if (num <= 0)
			{
				return 0;
			}
			if (EnableStatistics)
			{
				Statistics.IncrementPacketsSent();
				Statistics.AddBytesSent(length);
			}
			return num;
		}

		public bool SendBroadcast(NetDataWriter writer, int port)
		{
			return SendBroadcast(writer.Data, 0, writer.Length, port);
		}

		public bool SendBroadcast(byte[] data, int port)
		{
			return SendBroadcast(data, 0, data.Length, port);
		}

		public bool SendBroadcast(byte[] data, int start, int length, int port)
		{
			if (!IsRunning)
			{
				return false;
			}
			NetPacket netPacket;
			if (_extraPacketLayer != null)
			{
				int headerSize = NetPacket.GetHeaderSize(PacketProperty.Broadcast);
				netPacket = PoolGetPacket(headerSize + length + _extraPacketLayer.ExtraPacketSizeForLayer);
				netPacket.Property = PacketProperty.Broadcast;
				Buffer.BlockCopy(data, start, netPacket.RawData, headerSize, length);
				int offset = 0;
				int length2 = length + headerSize;
				IPEndPoint endPoint = null;
				_extraPacketLayer.ProcessOutBoundPacket(ref endPoint, ref netPacket.RawData, ref offset, ref length2);
			}
			else
			{
				netPacket = PoolGetWithData(PacketProperty.Broadcast, data, start, length);
			}
			bool flag = false;
			bool flag2 = false;
			try
			{
				flag = _udpSocketv4.SendTo(netPacket.RawData, 0, netPacket.Size, SocketFlags.None, new IPEndPoint(IPAddress.Broadcast, port)) > 0;
				if (_udpSocketv6 != null)
				{
					flag2 = _udpSocketv6.SendTo(netPacket.RawData, 0, netPacket.Size, SocketFlags.None, new IPEndPoint(MulticastAddressV6, port)) > 0;
				}
			}
			catch (SocketException ex)
			{
				if (ex.SocketErrorCode == SocketError.HostUnreachable)
				{
					return flag;
				}
				NetDebug.WriteError($"[S][MCAST] {ex}");
				return flag;
			}
			catch (Exception value)
			{
				NetDebug.WriteError($"[S][MCAST] {value}");
				return flag;
			}
			finally
			{
				PoolRecycle(netPacket);
			}
			return flag || flag2;
		}

		private void CloseSocket()
		{
			IsRunning = false;
			_udpSocketv4?.Close();
			_udpSocketv6?.Close();
			_udpSocketv4 = null;
			_udpSocketv6 = null;
			if (_receiveThread != null && _receiveThread != Thread.CurrentThread)
			{
				_receiveThread.Join();
			}
			_receiveThread = null;
		}
	}
	internal enum PacketProperty : byte
	{
		Unreliable,
		Channeled,
		Ack,
		Ping,
		Pong,
		ConnectRequest,
		ConnectAccept,
		Disconnect,
		UnconnectedMessage,
		MtuCheck,
		MtuOk,
		Broadcast,
		Merged,
		ShutdownOk,
		PeerNotFound,
		InvalidProtocol,
		NatMessage,
		Empty
	}
	internal sealed class NetPacket
	{
		private static readonly int PropertiesCount;

		private static readonly int[] HeaderSizes;

		public byte[] RawData;

		public int Size;

		public object UserData;

		public NetPacket Next;

		public PacketProperty Property
		{
			get
			{
				return (PacketProperty)(RawData[0] & 0x1Fu);
			}
			set
			{
				RawData[0] = (byte)((RawData[0] & 0xE0u) | (uint)value);
			}
		}

		public byte ConnectionNumber
		{
			get
			{
				return (byte)((RawData[0] & 0x60) >> 5);
			}
			set
			{
				RawData[0] = (byte)((RawData[0] & 0x9Fu) | (uint)(value << 5));
			}
		}

		public ushort Sequence
		{
			get
			{
				return BitConverter.ToUInt16(RawData, 1);
			}
			set
			{
				FastBitConverter.GetBytes(RawData, 1, value);
			}
		}

		public bool IsFragmented => (RawData[0] & 0x80) != 0;

		public byte ChannelId
		{
			get
			{
				return RawData[3];
			}
			set
			{
				RawData[3] = value;
			}
		}

		public ushort FragmentId
		{
			get
			{
				return BitConverter.ToUInt16(RawData, 4);
			}
			set
			{
				FastBitConverter.GetBytes(RawData, 4, value);
			}
		}

		public ushort FragmentPart
		{
			get
			{
				return BitConverter.ToUInt16(RawData, 6);
			}
			set
			{
				FastBitConverter.GetBytes(RawData, 6, value);
			}
		}

		public ushort FragmentsTotal
		{
			get
			{
				return BitConverter.ToUInt16(RawData, 8);
			}
			set
			{
				FastBitConverter.GetBytes(RawData, 8, value);
			}
		}

		static NetPacket()
		{
			PropertiesCount = Enum.GetValues(typeof(PacketProperty)).Length;
			HeaderSizes = NetUtils.AllocatePinnedUninitializedArray<int>(PropertiesCount);
			for (int i = 0; i < HeaderSizes.Length; i++)
			{
				switch ((PacketProperty)(byte)i)
				{
				case PacketProperty.Channeled:
				case PacketProperty.Ack:
					HeaderSizes[i] = 4;
					break;
				case PacketProperty.Ping:
					HeaderSizes[i] = 3;
					break;
				case PacketProperty.ConnectRequest:
					HeaderSizes[i] = 18;
					break;
				case PacketProperty.ConnectAccept:
					HeaderSizes[i] = 15;
					break;
				case PacketProperty.Disconnect:
					HeaderSizes[i] = 9;
					break;
				case PacketProperty.Pong:
					HeaderSizes[i] = 11;
					break;
				default:
					HeaderSizes[i] = 1;
					break;
				}
			}
		}

		public void MarkFragmented()
		{
			RawData[0] |= 128;
		}

		public NetPacket(int size)
		{
			RawData = new byte[size];
			Size = size;
		}

		public NetPacket(PacketProperty property, int size)
		{
			size += GetHeaderSize(property);
			RawData = new byte[size];
			Property = property;
			Size = size;
		}

		public static int GetHeaderSize(PacketProperty property)
		{
			return HeaderSizes[(uint)property];
		}

		public int GetHeaderSize()
		{
			return HeaderSizes[RawData[0] & 0x1F];
		}

		public bool Verify()
		{
			byte b = (byte)(RawData[0] & 0x1Fu);
			if (b >= PropertiesCount)
			{
				return false;
			}
			int num = HeaderSizes[b];
			bool flag = (RawData[0] & 0x80) != 0;
			if (Size >= num)
			{
				if (flag)
				{
					return Size >= num + 6;
				}
				return true;
			}
			return false;
		}

		public static implicit operator Span<byte>(NetPacket p)
		{
			return new Span<byte>(p.RawData, 0, p.Size);
		}
	}
	[Flags]
	public enum ConnectionState : byte
	{
		Outgoing = 2,
		Connected = 4,
		ShutdownRequested = 8,
		Disconnected = 0x10,
		EndPointChange = 0x20,
		Any = 0x2E
	}
	internal enum ConnectRequestResult
	{
		None,
		P2PLose,
		Reconnection,
		NewConnection
	}
	internal enum DisconnectResult
	{
		None,
		Reject,
		Disconnect
	}
	internal enum ShutdownResult
	{
		None,
		Success,
		WasConnected
	}
	public class NetPeer : IPEndPoint
	{
		private class IncomingFragments
		{
			public NetPacket[] Fragments;

			public int ReceivedCount;

			public int TotalSize;

			public byte ChannelId;
		}

		private int _rtt;

		private int _avgRtt;

		private int _rttCount;

		private double _resendDelay = 27.0;

		private float _pingSendTimer;

		private float _rttResetTimer;

		private readonly Stopwatch _pingTimer = new Stopwatch();

		private volatile float _timeSinceLastPacket;

		private long _remoteDelta;

		private readonly object _shutdownLock = new object();

		internal volatile NetPeer NextPeer;

		internal NetPeer PrevPeer;

		private NetPacket[] _unreliableSecondQueue;

		private NetPacket[] _unreliableChannel;

		private int _unreliablePendingCount;

		private readonly object _unreliableChannelLock = new object();

		private readonly ConcurrentQueue<BaseChannel> _channelSendQueue;

		private readonly BaseChannel[] _channels;

		private int _mtu;

		private int _mtuIdx;

		private bool _finishMtu;

		private float _mtuCheckTimer;

		private int _mtuCheckAttempts;

		private const int MtuCheckDelay = 1000;

		private const int MaxMtuCheckAttempts = 4;

		private readonly object _mtuMutex = new object();

		private int _fragmentId;

		private readonly Dictionary<ushort, IncomingFragments> _holdedFragments;

		private readonly Dictionary<ushort, ushort> _deliveredFragments;

		private readonly NetPacket _mergeData;

		private int _mergePos;

		private int _mergeCount;

		private int _connectAttempts;

		private float _connectTimer;

		private long _connectTime;

		private byte _connectNum;

		private ConnectionState _connectionState;

		private NetPacket _shutdownPacket;

		private const int ShutdownDelay = 300;

		private float _shutdownTimer;

		private readonly NetPacket _pingPacket;

		private readonly NetPacket _pongPacket;

		private readonly NetPacket _connectRequestPacket;

		private readonly NetPacket _connectAcceptPacket;

		public readonly NetManager NetManager;

		public readonly int Id;

		public object Tag;

		public readonly NetStatistics Statistics;

		private SocketAddress _cachedSocketAddr;

		private int _cachedHashCode;

		internal byte[] NativeAddress;

		internal byte ConnectionNum
		{
			get
			{
				return _connectNum;
			}
			private set
			{
				_connectNum = value;
				_mergeData.ConnectionNumber = value;
				_pingPacket.ConnectionNumber = value;
				_pongPacket.ConnectionNumber = value;
			}
		}

		public ConnectionState ConnectionState => _connectionState;

		internal long ConnectTime => _connectTime;

		public int RemoteId { get; private set; }

		public int Ping => _avgRtt / 2;

		public int RoundTripTime => _avgRtt;

		public int Mtu => _mtu;

		public long RemoteTimeDelta => _remoteDelta;

		public DateTime RemoteUtcTime => new DateTime(DateTime.UtcNow.Ticks + _remoteDelta);

		public float TimeSinceLastPacket => _timeSinceLastPacket;

		internal double ResendDelay => _resendDelay;

		public override SocketAddress Serialize()
		{
			return _cachedSocketAddr;
		}

		public override int GetHashCode()
		{
			return _cachedHashCode;
		}

		internal NetPeer(NetManager netManager, IPEndPoint remoteEndPoint, int id)
			: base(remoteEndPoint.Address, remoteEndPoint.Port)
		{
			Id = id;
			Statistics = new NetStatistics();
			NetManager = netManager;
			_cachedSocketAddr = base.Serialize();
			if (NetManager.UseNativeSockets)
			{
				NativeAddress = new byte[_cachedSocketAddr.Size];
				for (int i = 0; i < _cachedSocketAddr.Size; i++)
				{
					NativeAddress[i] = _cachedSocketAddr[i];
				}
			}
			_cachedHashCode = base.GetHashCode();
			ResetMtu();
			_connectionState = ConnectionState.Connected;
			_mergeData = new NetPacket(PacketProperty.Merged, NetConstants.MaxPacketSize);
			_pongPacket = new NetPacket(PacketProperty.Pong, 0);
			_pingPacket = new NetPacket(PacketProperty.Ping, 0)
			{
				Sequence = 1
			};
			_unreliableSecondQueue = new NetPacket[8];
			_unreliableChannel = new NetPacket[8];
			_holdedFragments = new Dictionary<ushort, IncomingFragments>();
			_deliveredFragments = new Dictionary<ushort, ushort>();
			_channels = new BaseChannel[netManager.ChannelsCount * 4];
			_channelSendQueue = new ConcurrentQueue<BaseChannel>();
		}

		internal void InitiateEndPointChange()
		{
			ResetMtu();
			_connectionState = ConnectionState.EndPointChange;
		}

		internal void FinishEndPointChange(IPEndPoint newEndPoint)
		{
			if (_connectionState != ConnectionState.EndPointChange)
			{
				return;
			}
			_connectionState = ConnectionState.Connected;
			base.Address = newEndPoint.Address;
			base.Port = newEndPoint.Port;
			if (NetManager.UseNativeSockets)
			{
				NativeAddress = new byte[_cachedSocketAddr.Size];
				for (int i = 0; i < _cachedSocketAddr.Size; i++)
				{
					NativeAddress[i] = _cachedSocketAddr[i];
				}
			}
			_cachedSocketAddr = base.Serialize();
			_cachedHashCode = base.GetHashCode();
		}

		internal void ResetMtu()
		{
			_finishMtu = !NetManager.MtuDiscovery;
			if (NetManager.MtuOverride > 0)
			{
				OverrideMtu(NetManager.MtuOverride);
			}
			else
			{
				SetMtu(0);
			}
		}

		private void SetMtu(int mtuIdx)
		{
			_mtuIdx = mtuIdx;
			_mtu = NetConstants.PossibleMtu[mtuIdx] - NetManager.ExtraPacketSizeForLayer;
		}

		private void OverrideMtu(int mtuValue)
		{
			_mtu = mtuValue;
			_finishMtu = true;
		}

		public int GetPacketsCountInReliableQueue(byte channelNumber, bool ordered)
		{
			int num = channelNumber * 4 + (ordered ? 2 : 0);
			BaseChannel baseChannel = _channels[num];
			if (baseChannel == null)
			{
				return 0;
			}
			return ((ReliableChannel)baseChannel).PacketsInQueue;
		}

		public PooledPacket CreatePacketFromPool(DeliveryMethod deliveryMethod, byte channelNumber)
		{
			int mtu = _mtu;
			NetPacket netPacket = NetManager.PoolGetPacket(mtu);
			if (deliveryMethod == DeliveryMethod.Unreliable)
			{
				netPacket.Property = PacketProperty.Unreliable;
				return new PooledPacket(netPacket, mtu, 0);
			}
			netPacket.Property = PacketProperty.Channeled;
			return new PooledPacket(netPacket, mtu, (byte)((uint)(channelNumber * 4) + (ui