Decompiled source of LobbyControl v2.5.12

BepInEx/plugins/LobbyControl.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using HarmonyLib.Public.Patching;
using JetBrains.Annotations;
using LethalConfig;
using LethalConfig.ConfigItems;
using LethalConfig.ConfigItems.Options;
using LobbyCompatibility.Enums;
using LobbyCompatibility.Features;
using LobbyControl.API;
using LobbyControl.Dependency;
using LobbyControl.Networking;
using LobbyControl.Patches;
using LobbyControl.PopUp;
using LobbyControl.TerminalCommands;
using LobbyControl.Utils;
using LobbyControl.Utils.IL;
using Microsoft.CodeAnalysis;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;
using MonoMod.RuntimeDetour;
using MonoMod.Utils;
using Netcode.Transports.Facepunch;
using Steamworks;
using Steamworks.Data;
using TMPro;
using Unity.Collections;
using Unity.Netcode;
using Unity.Netcode.Transports.UTP;
using Unity.Networking.Transport;
using UnityEngine;
using UnityEngine.Pool;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("AmazingAssets.TerrainToMesh")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("ClientNetworkTransform")]
[assembly: IgnoresAccessChecksTo("com.olegknyazev.softmask")]
[assembly: IgnoresAccessChecksTo("DissonanceVoip")]
[assembly: IgnoresAccessChecksTo("DunGen")]
[assembly: IgnoresAccessChecksTo("DunGen.Integration.ASPP")]
[assembly: IgnoresAccessChecksTo("DunGen.Integration.UnityNav")]
[assembly: IgnoresAccessChecksTo("EasyTextEffects")]
[assembly: IgnoresAccessChecksTo("Facepunch Transport for Netcode for GameObjects")]
[assembly: IgnoresAccessChecksTo("Facepunch.Steamworks.Win64")]
[assembly: IgnoresAccessChecksTo("Unity.AI.Navigation")]
[assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging")]
[assembly: IgnoresAccessChecksTo("Unity.Animation.Rigging.DocCodeExamples")]
[assembly: IgnoresAccessChecksTo("Unity.Burst")]
[assembly: IgnoresAccessChecksTo("Unity.Burst.Unsafe")]
[assembly: IgnoresAccessChecksTo("Unity.Collections")]
[assembly: IgnoresAccessChecksTo("Unity.Collections.LowLevel.ILSupport")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem.ForUI")]
[assembly: IgnoresAccessChecksTo("Unity.Jobs")]
[assembly: IgnoresAccessChecksTo("Unity.Mathematics")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.Common")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.MetricTypes")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStats")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Component")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Configuration")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsMonitor.Implementation")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetStatsReporting")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkProfiler.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.Multiplayer.Tools.NetworkSolutionInterface")]
[assembly: IgnoresAccessChecksTo("Unity.Netcode.Components")]
[assembly: IgnoresAccessChecksTo("Unity.Netcode.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.Networking.Transport")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Csg")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.KdTree")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Poly2Tri")]
[assembly: IgnoresAccessChecksTo("Unity.ProBuilder.Stl")]
[assembly: IgnoresAccessChecksTo("Unity.Profiling.Core")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.ShaderLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Config.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.HighDefinition.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Authentication")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Analytics")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Components")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Configuration")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Device")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Environments.Internal")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Internal")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Networking")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Registration")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Scheduler")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Telemetry")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Core.Threading")]
[assembly: IgnoresAccessChecksTo("Unity.Services.QoS")]
[assembly: IgnoresAccessChecksTo("Unity.Services.Relay")]
[assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")]
[assembly: IgnoresAccessChecksTo("Unity.Timeline")]
[assembly: IgnoresAccessChecksTo("Unity.VisualEffectGraph.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.XR.CoreUtils")]
[assembly: IgnoresAccessChecksTo("Unity.XR.Management")]
[assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR")]
[assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.ConformanceAutomation")]
[assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.MetaQuestSupport")]
[assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.MockRuntime")]
[assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.OculusQuestSupport")]
[assembly: IgnoresAccessChecksTo("Unity.XR.OpenXR.Features.RuntimeDebugger")]
[assembly: IgnoresAccessChecksTo("UnityEngine.ARModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.NVIDIAModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.SpatialTracking")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UI")]
[assembly: IgnoresAccessChecksTo("UnityEngine.XR.LegacyInputHelpers")]
[assembly: AssemblyCompany("mattymatty")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("2.5.12")]
[assembly: AssemblyInformationalVersion("2.5.12+71c015f4c339daeda77c450162c119fd8080f7dd")]
[assembly: AssemblyProduct("LobbyControl")]
[assembly: AssemblyTitle("LobbyControl - Plugin")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.5.12.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class IsUnmanagedAttribute : Attribute
	{
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace LobbyControl
{
	[BepInPlugin("mattymatty.LobbyControl", "LobbyControl", "2.5.12")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	internal class LobbyControl : BaseUnityPlugin
	{
		public const string GUID = "mattymatty.LobbyControl";

		public const string NAME = "LobbyControl";

		public const string VERSION = "2.5.12";

		public static LobbyControl Instance;

		internal static ManualLogSource Log;

		public static bool CanModifyLobby = true;

		public static bool CanSave = true;

		public static bool AutoSaveEnabled = true;

		private static readonly string[] IncompatibleGUIDs = new string[4] { "com.github.tinyhoot.ShipLobby", "twig.latecompany", "McBowie.VeryLateCompany", "com.potatoepet.AdvancedCompany" };

		internal static readonly List<PluginInfo> FoundIncompatibilities = new List<PluginInfo>();

		internal static Harmony Harmony { get; private set; }

		internal static HashSet<Hook> Hooks { get; } = new HashSet<Hook>();

		private void Awake()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			try
			{
				Harmony = new Harmony("mattymatty.LobbyControl");
				PluginInfo[] array = Chainloader.PluginInfos.Values.Where((PluginInfo p) => IncompatibleGUIDs.Contains(p.Metadata.GUID)).ToArray();
				if (array.Length != 0)
				{
					StringBuilder stringBuilder = new StringBuilder("LOBBY CONTROL was DISABLED!\nIncompatible:");
					FoundIncompatibilities.AddRange(array);
					PluginInfo[] array2 = array;
					foreach (PluginInfo val in array2)
					{
						Log.LogWarning((object)(val.Metadata.Name + " is incompatible!"));
						stringBuilder.Append("\n").Append(val.Metadata.Name);
					}
					Log.LogError((object)$"{array.Length} incompatible mods found! Disabling!");
					PopUpPatch.PopUps.Add(("LC_Incompatibility", stringBuilder.ToString()));
					Harmony.PatchAll(typeof(PopUpPatch));
					return;
				}
				if (LobbyCompatibilityChecker.Enabled)
				{
					LobbyCompatibilityChecker.Init("mattymatty.LobbyControl", Version.Parse("2.5.12"), 1, 2);
				}
				Log.LogInfo((object)"Initializing Configs");
				PluginConfig.Init((BaseUnityPlugin)(object)this);
				CommandManager.Initialize();
				LobbyCommand.Init();
				Log.LogInfo((object)"Patching Methods");
				Harmony.PatchAll(typeof(PopUpPatch));
				Harmony.PatchAll(typeof(FacepunchTransportPatches));
				Harmony.PatchAll(typeof(JoinQueuePatches));
				JoinQueuePatches.Init();
				Harmony.PatchAll(typeof(LateJoinPatches));
				Harmony.PatchAll(typeof(LimitPatcher));
				Harmony.PatchAll(typeof(LobbyPatcher));
				Harmony.PatchAll(typeof(LogSpamPatches));
				Harmony.PatchAll(typeof(NetworkManagerPatch));
				Harmony.PatchAll(typeof(SavePatches));
				Harmony.PatchAll(typeof(TerminalPatch));
				Log.LogInfo((object)"LobbyControl v2.5.12 Loaded!");
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Exception while initializing: \n" + ex));
			}
		}
	}
	internal static class PluginConfig
	{
		internal static class SteamLobby
		{
			internal static ConfigEntry<bool> AutoLobby;
		}

		internal static class SaveLimit
		{
			internal static ConfigEntry<bool> Enabled;
		}

		internal static class LogSpam
		{
			internal static ConfigEntry<bool> Enabled;

			internal static ConfigEntry<bool> CalculatePolygonPath;
		}

		internal static class JoinQueue
		{
			internal static ConfigEntry<bool> Enabled;

			internal static ConfigEntry<int> MaxSize;

			internal static ConfigEntry<int> ConnectionTimeout;

			internal static ConfigEntry<bool> TimeoutPopup;

			internal static ConfigEntry<bool> ConnectionPopup;

			internal static ConfigEntry<int> PreLobbyChannel;
		}

		internal static class Networking
		{
			internal static ConfigEntry<bool> Enabled;

			internal static ConfigEntry<bool> SyncRadarNames;

			internal static ConfigEntry<bool> ResetPlayerValues;
		}

		internal static void Init(BaseUnityPlugin plugin)
		{
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Expected O, but got Unknown
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Expected O, but got Unknown
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Expected O, but got Unknown
			ConfigFile config = plugin.Config;
			config.SaveOnConfigSet = false;
			SaveLimit.Enabled = config.Bind<bool>("SaveLimit", "enabled", true, "remove the limit to the amount of items that can be saved");
			SteamLobby.AutoLobby = config.Bind<bool>("SteamLobby", "auto_lobby", false, "automatically reopen the lobby as soon as you reach orbit");
			LogSpam.Enabled = config.Bind<bool>("LogSpam", "enabled", true, "prevent some annoying log spam");
			LogSpam.CalculatePolygonPath = config.Bind<bool>("LogSpam", "CalculatePolygonPath", true, "stop pathfinding for dead Enemies");
			JoinQueue.Enabled = config.Bind<bool>("JoinQueue", "enabled", true, "handle joining players as a queue instead of at the same time");
			JoinQueue.MaxSize = config.Bind<int>("JoinQueue", "max_size", 3, new ConfigDescription("max number of players in queue ( if queue is full extra connections will be refused )", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 65535), Array.Empty<object>()));
			JoinQueue.ConnectionTimeout = config.Bind<int>("JoinQueue", "connection_timeout_ms", 40000, new ConfigDescription("After how much time discard a hanging connection", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10000, int.MaxValue), Array.Empty<object>()));
			JoinQueue.TimeoutPopup = config.Bind<bool>("JoinQueue", "timeout_notification", true, "show a popup when a client fails to join before the timeout");
			JoinQueue.ConnectionPopup = config.Bind<bool>("JoinQueue", "connection_notification", false, "show a popup when a client tries to join");
			JoinQueue.PreLobbyChannel = config.Bind<int>("JoinQueue", "pre-lobby_channel", 28, new ConfigDescription("channel to use for pre-lobby connections", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 255), Array.Empty<object>()));
			Networking.Enabled = config.Bind<bool>("Networking", "enabled", true, "handle extra actions requested by host");
			Networking.SyncRadarNames = config.Bind<bool>("Networking", "sync_radar_names", false, "allow host to reorder radar names to align clients\nWARNING: all clients need to have the mod installed or desyncs might will happen");
			Networking.ResetPlayerValues = config.Bind<bool>("Networking", "reset_player_values", true, "allow host to force clients to reset most fields of a playerObject ( fix for invisible players )");
			JoinQueue.ConnectionTimeout.SettingChanged += delegate
			{
				NetworkManager singleton = NetworkManager.Singleton;
				if (singleton != null)
				{
					singleton.NetworkConfig.ClientConnectionBufferTimeout = JoinQueue.ConnectionTimeout.Value / 1000 * 4;
				}
			};
			if (LethalConfigProxy.Enabled)
			{
				LethalConfigProxy.AddConfig(SaveLimit.Enabled);
				LethalConfigProxy.AddConfig(SteamLobby.AutoLobby);
				LethalConfigProxy.AddConfig(LogSpam.Enabled);
				LethalConfigProxy.AddConfig(LogSpam.CalculatePolygonPath);
				LethalConfigProxy.AddConfig(JoinQueue.Enabled);
				LethalConfigProxy.AddConfig(JoinQueue.MaxSize);
				LethalConfigProxy.AddConfig(JoinQueue.ConnectionTimeout);
				LethalConfigProxy.AddConfig(JoinQueue.TimeoutPopup);
				LethalConfigProxy.AddConfig(JoinQueue.ConnectionPopup);
				LethalConfigProxy.AddConfig(JoinQueue.PreLobbyChannel);
				LethalConfigProxy.AddConfig(Networking.Enabled);
				LethalConfigProxy.AddConfig(Networking.SyncRadarNames);
				LethalConfigProxy.AddConfig(Networking.ResetPlayerValues);
			}
			PropertyInfo property = ((object)config).GetType().GetProperty("OrphanedEntries", BindingFlags.Instance | BindingFlags.NonPublic);
			Dictionary<ConfigDefinition, string> dictionary = (Dictionary<ConfigDefinition, string>)property.GetValue(config, null);
			dictionary.Clear();
			config.Save();
			config.SaveOnConfigSet = true;
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "mattymatty.LobbyControl";

		public const string PLUGIN_NAME = "LobbyControl";

		public const string PLUGIN_VERSION = "2.5.12";
	}
}
namespace LobbyControl.Utils
{
	public class FreeRunningTimer
	{
		private readonly Stopwatch _stopwatch = new Stopwatch();

		private TimeSpan _timeout = TimeSpan.Zero;

		public bool Enabled => _stopwatch.IsRunning;

		public bool TimedOut => _stopwatch.Elapsed > _timeout;

		public TimeSpan Elapsed => _stopwatch.Elapsed;

		public TimeSpan Remaining
		{
			get
			{
				if (!TimedOut)
				{
					return _timeout - _stopwatch.Elapsed;
				}
				return TimeSpan.Zero;
			}
		}

		public void Start(TimeSpan timeout)
		{
			_timeout = timeout;
			_stopwatch.Restart();
		}

		public void Stop()
		{
			_stopwatch.Stop();
		}
	}
	public static class HudUtils
	{
		private static readonly WaitUntil WaitForAnimation = new WaitUntil((Func<bool>)delegate
		{
			//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)
			AnimatorStateInfo currentAnimatorStateInfo = HUDManager.Instance.tipsPanelAnimator.GetCurrentAnimatorStateInfo(0);
			return ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime >= 1f;
		});

		internal static IEnumerator ShowMessageAfterDelay(string title, string text, float delay = 0f, bool isWarning = false)
		{
			if (delay > 0f)
			{
				yield return (object)new WaitForSeconds(delay);
			}
			yield return WaitForAnimation;
			HUDManager.Instance.DisplayTip(title, text, isWarning, false, "LC_Tip1");
		}

		internal static IEnumerator ShowTipAfterDelay(string title, string text, float delay, string saveKey)
		{
			if (delay > 0f)
			{
				yield return (object)new WaitForSeconds(delay);
			}
			yield return WaitForAnimation;
			HUDManager.Instance.DisplayTip(title, text, false, true, saveKey);
		}
	}
	public static class RPCUtils
	{
		private static readonly MethodInfo BeginSendClientRpc = AccessTools.Method(typeof(NetworkBehaviour), "__beginSendClientRpc", (Type[])null, (Type[])null);

		private static readonly MethodInfo BeginSendServerRpc = AccessTools.Method(typeof(NetworkBehaviour), "__beginSendServerRpc", (Type[])null, (Type[])null);

		internal static bool TryGetRpcID(MethodInfo methodInfo, out uint rpcID)
		{
			//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_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			Collection<Instruction> instructions = PatchManager.GetMethodPatcher((MethodBase)methodInfo).CopyOriginal().Definition.Body.Instructions;
			rpcID = 0u;
			for (int i = 0; i < instructions.Count; i++)
			{
				if (instructions[i].OpCode == OpCodes.Ldc_I4 && instructions[i - 1].OpCode == OpCodes.Ldarg_0)
				{
					rpcID = (uint)(int)instructions[i].Operand;
				}
				if (!(instructions[i].OpCode != OpCodes.Call))
				{
					object operand = instructions[i].Operand;
					MethodReference val = (MethodReference)((operand is MethodReference) ? operand : null);
					if (val != null && (Extensions.Is((MemberReference)(object)val, (MemberInfo)BeginSendClientRpc) || Extensions.Is((MemberReference)(object)val, (MemberInfo)BeginSendServerRpc)))
					{
						LobbyControl.Log.LogDebug((object)$"Rpc Id found for {methodInfo.Name}: {rpcID}U");
						return true;
					}
				}
			}
			LobbyControl.Log.LogFatal((object)("Cannot find Rpc ID for " + methodInfo.Name));
			return false;
		}
	}
}
namespace LobbyControl.Utils.IL
{
	internal class ILInjector
	{
		private const string INVALID = "Injector is invalid";

		private List<CodeInstruction> instructions = instructions.ToList();

		private ILGenerator generator;

		private int index;

		private int matchEnd;

		public int Index
		{
			get
			{
				return index;
			}
			set
			{
				index = value;
			}
		}

		public bool IsValid
		{
			get
			{
				if (instructions != null)
				{
					return IsIndexValid(index);
				}
				return false;
			}
		}

		public CodeInstruction Instruction
		{
			get
			{
				if (!IsIndexInRange(index))
				{
					return null;
				}
				return instructions[index];
			}
			set
			{
				if (!IsIndexInRange(index))
				{
					throw new InvalidOperationException($"Current index {index} is out of range of instruction count {instructions.Count}");
				}
				instructions[index] = value;
			}
		}

		public CodeInstruction LastMatchedInstruction
		{
			get
			{
				int num = matchEnd - 1;
				if (!IsIndexInRange(num))
				{
					return null;
				}
				return instructions[num];
			}
			set
			{
				int num = matchEnd - 1;
				if (!IsIndexInRange(num))
				{
					throw new InvalidOperationException($"Last matched index {index} is out of range of instruction count {instructions.Count}");
				}
				instructions[num] = value;
			}
		}

		public ICollection<CodeInstruction> Instructions => instructions.AsReadOnly();

		public ILInjector(IEnumerable<CodeInstruction> instructions, ILGenerator generator = null)
		{
			this.generator = generator;
			matchEnd = -1;
			base..ctor();
		}

		public ILInjector GoToStart()
		{
			matchEnd = index;
			index = 0;
			return this;
		}

		public ILInjector GoToEnd()
		{
			matchEnd = index;
			index = instructions.Count;
			return this;
		}

		public ILInjector Forward(int offset)
		{
			if (!IsValid)
			{
				return this;
			}
			matchEnd = index;
			index = Math.Clamp(index + offset, -1, instructions.Count);
			return this;
		}

		public ILInjector Back(int offset)
		{
			return Forward(-offset);
		}

		private void MarkInvalid()
		{
			index = -1;
			matchEnd = -1;
		}

		private void Search(bool forward, ILMatcher[] predicates)
		{
			if (!IsValid)
			{
				return;
			}
			int num = 1;
			if (!forward)
			{
				num = -1;
				index--;
			}
			while (forward ? (index < instructions.Count) : (index >= 0))
			{
				if (forward && index + predicates.Length > instructions.Count)
				{
					index = instructions.Count;
					break;
				}
				int i;
				for (i = 0; i < predicates.Length && predicates[i].Matches(instructions[index + i]); i++)
				{
				}
				if (i == predicates.Length)
				{
					matchEnd = index + i;
					return;
				}
				index += num;
			}
			MarkInvalid();
		}

		public ILInjector Find(params ILMatcher[] predicates)
		{
			Search(forward: true, predicates);
			return this;
		}

		public ILInjector ReverseFind(params ILMatcher[] predicates)
		{
			Search(forward: false, predicates);
			return this;
		}

		public ILInjector GoToPush(int popIndex)
		{
			if (!IsValid)
			{
				return this;
			}
			matchEnd = index;
			index--;
			int num = 0;
			while (index >= 0)
			{
				CodeInstruction instruction = instructions[index];
				num += instruction.PushCount();
				num -= instruction.PopCount();
				if (num >= popIndex)
				{
					return this;
				}
				index--;
			}
			return this;
		}

		public ILInjector SkipBranch()
		{
			if (Instruction == null)
			{
				return this;
			}
			if (!(Instruction.operand is Label label))
			{
				throw new InvalidOperationException($"Current instruction is not a branch: {Instruction}");
			}
			return FindLabel(label);
		}

		public ILInjector FindLabel(Label label)
		{
			if (label == default(Label))
			{
				return this;
			}
			matchEnd = index;
			for (index = 0; index < instructions.Count; index++)
			{
				if (instructions[index].labels.Contains(label))
				{
					return this;
				}
			}
			MarkInvalid();
			return this;
		}

		public ILInjector GoToMatchEnd()
		{
			index = matchEnd;
			return this;
		}

		public ILInjector GoToLastMatchedInstruction()
		{
			if (!IsIndexValid(matchEnd))
			{
				return this;
			}
			index = matchEnd - 1;
			return this;
		}

		private bool IsIndexValid(int index)
		{
			return index != -1;
		}

		private bool IsIndexInRange(int index)
		{
			if (index >= 0)
			{
				return index < instructions.Count;
			}
			return false;
		}

		public CodeInstruction GetRelativeInstruction(int offset)
		{
			if (!IsValid)
			{
				throw new InvalidOperationException("Injector is invalid");
			}
			int num = index + offset;
			if (!IsIndexInRange(num))
			{
				throw new IndexOutOfRangeException($"Offset {offset} would read out of bounds at index {num}");
			}
			return instructions[num];
		}

		public ILInjector SetRelativeInstruction(int offset, CodeInstruction instruction)
		{
			if (!IsValid)
			{
				throw new InvalidOperationException("Injector is invalid");
			}
			int num = index + offset;
			if (!IsIndexInRange(num))
			{
				throw new IndexOutOfRangeException($"Offset {offset} would write out of bounds at index {num}");
			}
			instructions[num] = instruction;
			return this;
		}

		public IEnumerable<CodeInstruction> GetRelativeInstructions(int offset, int size)
		{
			for (int i = 0; i < size; i++)
			{
				yield return instructions[index + offset + i];
			}
		}

		public IEnumerable<CodeInstruction> GetRelativeInstructions(int size)
		{
			return GetRelativeInstructions(0, size);
		}

		private void GetLastMatchRangeAbsolute(out int start, out int end)
		{
			start = index;
			end = matchEnd;
			if (start > end)
			{
				int num = end;
				int num2 = start;
				start = num;
				end = num2;
			}
		}

		private void GetLastMatchRange(out int start, out int size)
		{
			GetLastMatchRangeAbsolute(out start, out var end);
			if (start < 0 || start >= instructions.Count)
			{
				throw new InvalidOperationException($"Last match range starts at invalid index {start}");
			}
			if (end < 0 || end > instructions.Count)
			{
				throw new InvalidOperationException($"Last match range ends at invalid index {end}");
			}
			size = end - start;
		}

		public List<CodeInstruction> GetLastMatch()
		{
			GetLastMatchRange(out var start, out var size);
			return instructions.GetRange(start, size);
		}

		public ILInjector DefineLabel(out Label label)
		{
			if (generator == null)
			{
				throw new InvalidOperationException("No ILGenerator was provided");
			}
			label = generator.DefineLabel();
			return this;
		}

		public ILInjector AddLabel(out Label label)
		{
			DefineLabel(out label);
			return AddLabel(label);
		}

		public ILInjector AddLabel(Label label)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			Instruction = new CodeInstruction(Instruction);
			Instruction.labels.Add(label);
			return this;
		}

		public ILInjector InsertInPlace(params CodeInstruction[] instructions)
		{
			if (!IsValid)
			{
				throw new InvalidOperationException("Injector is invalid");
			}
			this.instructions.InsertRange(index, instructions);
			if (matchEnd >= index)
			{
				matchEnd += instructions.Length;
			}
			return this;
		}

		public ILInjector Insert(params CodeInstruction[] instructions)
		{
			InsertInPlace(instructions);
			index += instructions.Length;
			return this;
		}

		public ILInjector InsertInPlaceAfterBranch(params CodeInstruction[] instructions)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			if (!IsValid)
			{
				throw new InvalidOperationException("Injector is invalid");
			}
			List<Label> labels = Instruction.labels;
			Instruction = new CodeInstruction(Instruction);
			Instruction.labels.Clear();
			this.instructions.InsertRange(index, instructions);
			Instruction.labels.AddRange(labels);
			if (matchEnd >= index)
			{
				matchEnd += instructions.Length;
			}
			return this;
		}

		public ILInjector InsertAfterBranch(params CodeInstruction[] instructions)
		{
			InsertInPlaceAfterBranch(instructions);
			index += instructions.Length;
			return this;
		}

		public ILInjector RemoveAllPreviousInstructions()
		{
			if (!IsValid)
			{
				throw new InvalidOperationException("Injector is invalid");
			}
			instructions.RemoveRange(0, index);
			matchEnd -= index;
			if (matchEnd < 0)
			{
				matchEnd = 0;
			}
			index = 0;
			return this;
		}

		public ILInjector Remove(int count = 1)
		{
			if (!IsValid)
			{
				throw new InvalidOperationException("Injector is invalid");
			}
			instructions.RemoveRange(index, count);
			if (matchEnd > index)
			{
				matchEnd = Math.Max(index, matchEnd - count);
			}
			return this;
		}

		public ILInjector RemoveLastMatch()
		{
			GetLastMatchRange(out var start, out var size);
			List<Label> labels = instructions[start].labels;
			instructions.RemoveRange(start, size);
			index = start;
			matchEnd = start;
			instructions[start].labels.AddRange(labels);
			return this;
		}

		public ILInjector ReplaceLastMatch(params CodeInstruction[] replacementInstructions)
		{
			if (replacementInstructions.Length == 0)
			{
				throw new ArgumentException("Cannot replace a match with an empty array.");
			}
			GetLastMatchRange(out var start, out var size);
			List<Label> labels = instructions[start].labels;
			instructions.RemoveRange(start, size);
			instructions.InsertRange(start, replacementInstructions);
			index = start;
			matchEnd = start + replacementInstructions.Length;
			instructions[start].labels.AddRange(labels);
			return this;
		}

		public List<CodeInstruction> ReleaseInstructions()
		{
			List<CodeInstruction> result = instructions;
			instructions = null;
			return result;
		}

		public ILInjector PrintContext(int context, string header = "")
		{
			if (!IsValid)
			{
				throw new InvalidOperationException("Injector is invalid (" + header + ")");
			}
			StringBuilder stringBuilder = new StringBuilder(header);
			if (header.Length > 0)
			{
				stringBuilder.Append(':');
			}
			stringBuilder.AppendLine();
			GetLastMatchRangeAbsolute(out var start, out var end);
			int num = Math.Min(end + 1 + context, instructions.Count);
			for (int i = Math.Max(start - context, 0); i < num; i++)
			{
				if (end == -1 && i == index)
				{
					stringBuilder.Append("╶> ");
				}
				else
				{
					if (i >= start && i < end)
					{
						stringBuilder.Append("│");
					}
					else
					{
						stringBuilder.Append(" ");
					}
					if (i == index)
					{
						stringBuilder.Append("╶> ");
					}
					else
					{
						stringBuilder.Append("   ");
					}
				}
				stringBuilder.AppendLine($"{i}: {instructions[i]}");
			}
			LobbyControl.Log.LogFatal((object)stringBuilder);
			return this;
		}

		public ILInjector PrintContext(string header = "")
		{
			return PrintContext(4, header);
		}
	}
	internal interface ILMatcher
	{
		bool Matches(CodeInstruction instruction);

		ILMatcher CaptureAs(out CodeInstruction variable)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Expected O, but got Unknown
			variable = new CodeInstruction(OpCodes.Nop, (object)null);
			return new InstructionCapturingMatcher(this, variable);
		}

		unsafe ILMatcher CaptureOperandAs<T>(out T operand) where T : unmanaged
		{
			operand = default(T);
			fixed (T* operand2 = &operand)
			{
				return new OperandCapturingMatcher<T>(this, operand2);
			}
		}

		static ILMatcher Not(ILMatcher matcher)
		{
			return new NotMatcher(matcher);
		}

		static ILMatcher Opcode(OpCode opcode)
		{
			return new OpcodeMatcher(opcode);
		}

		static ILMatcher Opcodes(params OpCode[] opcodes)
		{
			return new OpcodesMatcher(opcodes);
		}

		static ILMatcher OpcodeOperand(OpCode opcode, object operand)
		{
			return new OpcodeOperandMatcher(opcode, operand);
		}

		static ILMatcher Instruction(CodeInstruction instruction)
		{
			return new InstructionMatcher(instruction);
		}

		static ILMatcher Ldarg(int? arg = null)
		{
			return new LdargMatcher(arg);
		}

		static ILMatcher Ldloc(int? loc = null)
		{
			return new LdlocMatcher(loc);
		}

		static ILMatcher Stloc(int? loc = null)
		{
			return new StlocMatcher(loc);
		}

		static ILMatcher Ldc(int? value = null)
		{
			return new LdcI32Matcher(value);
		}

		static ILMatcher Branch()
		{
			return new BranchMatcher();
		}

		static ILMatcher Ldfld(FieldInfo field, [CallerMemberName] string callerName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
		{
			if (field == null)
			{
				LobbyControl.Log.LogWarning((object)$"Field passed to ILMatcher.Ldfld() was null at {sourceFilePath}#{sourceLineNumber} ({callerName})");
			}
			return new OpcodeOperandMatcher(OpCodes.Ldfld, field);
		}

		static ILMatcher Ldsfld(FieldInfo field, [CallerMemberName] string callerName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
		{
			if (field == null)
			{
				LobbyControl.Log.LogWarning((object)$"Field passed to ILMatcher.Ldsfld() was null at {sourceFilePath}#{sourceLineNumber} ({callerName})");
			}
			return new OpcodeOperandMatcher(OpCodes.Ldsfld, field);
		}

		static ILMatcher Stfld(FieldInfo field, [CallerMemberName] string callerName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
		{
			if (field == null)
			{
				LobbyControl.Log.LogWarning((object)$"Field passed to ILMatcher.Stfld() was null at {sourceFilePath}#{sourceLineNumber} ({callerName})");
			}
			return new OpcodeOperandMatcher(OpCodes.Stfld, field);
		}

		static ILMatcher Stsfld(FieldInfo field, [CallerMemberName] string callerName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
		{
			if (field == null)
			{
				LobbyControl.Log.LogWarning((object)$"Field passed to ILMatcher.Stsfld() was null at {sourceFilePath}#{sourceLineNumber} ({callerName})");
			}
			return new OpcodeOperandMatcher(OpCodes.Stsfld, field);
		}

		static ILMatcher Callvirt(MethodBase method, [CallerMemberName] string callerName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
		{
			if (method == null)
			{
				LobbyControl.Log.LogWarning((object)$"Method passed to ILMatcher.Callvirt() was null at {sourceFilePath}#{sourceLineNumber} ({callerName})");
			}
			return OpcodeOperand(OpCodes.Callvirt, method);
		}

		static ILMatcher Call(MethodBase method, [CallerMemberName] string callerName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
		{
			if (method == null)
			{
				LobbyControl.Log.LogWarning((object)$"Method passed to ILMatcher.Call() was null at {sourceFilePath}#{sourceLineNumber} ({callerName})");
			}
			return OpcodeOperand(OpCodes.Call, method);
		}

		static ILMatcher Predicate(Func<CodeInstruction, bool> predicate)
		{
			return new PredicateMatcher(predicate);
		}

		static ILMatcher Predicate(Func<FieldInfo, bool> predicate)
		{
			return new PredicateMatcher((CodeInstruction insn) => insn.operand is FieldInfo arg && predicate(arg));
		}
	}
	internal class NotMatcher(ILMatcher matcher) : ILMatcher
	{
		private readonly ILMatcher matcher = matcher;

		public bool Matches(CodeInstruction instruction)
		{
			return !matcher.Matches(instruction);
		}
	}
	internal class OpcodeMatcher(OpCode opcode) : ILMatcher
	{
		private readonly OpCode opcode = opcode;

		public bool Matches(CodeInstruction instruction)
		{
			return instruction.opcode == opcode;
		}
	}
	internal class OpcodesMatcher(OpCode[] opcodes) : ILMatcher
	{
		private readonly OpCode[] opcodes = opcodes;

		public bool Matches(CodeInstruction instruction)
		{
			return opcodes.Contains(instruction.opcode);
		}
	}
	internal class OpcodeOperandMatcher(OpCode opcode, object operand) : ILMatcher
	{
		private readonly OpCode opcode = opcode;

		private readonly object operand = operand;

		public bool Matches(CodeInstruction instruction)
		{
			if (instruction.opcode == opcode)
			{
				return instruction.operand == operand;
			}
			return false;
		}
	}
	internal class InstructionMatcher : ILMatcher
	{
		private readonly OpCode opcode = instruction.opcode;

		private readonly object operand = instruction.operand;

		private readonly Label[] labels = instruction.labels.ToArray();

		public InstructionMatcher(CodeInstruction instruction)
		{
		}

		public bool Matches(CodeInstruction instruction)
		{
			if (instruction.opcode != opcode)
			{
				return false;
			}
			if (instruction.operand != operand)
			{
				return false;
			}
			if (instruction.labels.Count != labels.Length)
			{
				return false;
			}
			for (int i = 0; i < labels.Length; i++)
			{
				if (labels[i] != instruction.labels[i])
				{
					return false;
				}
			}
			return true;
		}
	}
	internal class LdargMatcher(int? arg) : ILMatcher
	{
		private readonly int? arg = arg;

		public bool Matches(CodeInstruction instruction)
		{
			if (!arg.HasValue)
			{
				return instruction.GetLdargIndex().HasValue;
			}
			return instruction.GetLdargIndex() == arg;
		}
	}
	internal class LdlocMatcher(int? loc) : ILMatcher
	{
		private readonly int? loc = loc;

		public bool Matches(CodeInstruction instruction)
		{
			if (!loc.HasValue)
			{
				return instruction.GetLdlocIndex().HasValue;
			}
			return instruction.GetLdlocIndex() == loc;
		}
	}
	internal class StlocMatcher(int? loc) : ILMatcher
	{
		private readonly int? loc = loc;

		public bool Matches(CodeInstruction instruction)
		{
			if (!loc.HasValue)
			{
				return instruction.GetStlocIndex().HasValue;
			}
			return instruction.GetStlocIndex() == loc;
		}
	}
	internal class LdcI32Matcher(int? value) : ILMatcher
	{
		private readonly int? value = value;

		public bool Matches(CodeInstruction instruction)
		{
			if (!value.HasValue)
			{
				return instruction.GetLdcI32().HasValue;
			}
			return instruction.GetLdcI32() == value;
		}
	}
	internal class BranchMatcher : ILMatcher
	{
		public bool Matches(CodeInstruction instruction)
		{
			Label? label = default(Label?);
			return CodeInstructionExtensions.Branches(instruction, ref label);
		}
	}
	internal class PredicateMatcher(Func<CodeInstruction, bool> predicate) : ILMatcher
	{
		private readonly Func<CodeInstruction, bool> predicate = predicate;

		public bool Matches(CodeInstruction instruction)
		{
			return predicate(instruction);
		}
	}
	internal class InstructionCapturingMatcher(ILMatcher matcher, CodeInstruction variable) : ILMatcher
	{
		private readonly ILMatcher matcher = matcher;

		private readonly CodeInstruction variable = variable;

		public bool Matches(CodeInstruction instruction)
		{
			bool flag = matcher.Matches(instruction);
			if (flag)
			{
				variable.opcode = instruction.opcode;
				variable.operand = instruction.operand;
				variable.blocks = instruction.blocks.ToList();
				variable.labels = instruction.labels.ToList();
			}
			return flag;
		}
	}
	internal unsafe class OperandCapturingMatcher<T>(ILMatcher matcher, T* operand) : ILMatcher where T : unmanaged
	{
		private readonly ILMatcher matcher = matcher;

		private unsafe readonly T* operand = operand;

		public unsafe bool Matches(CodeInstruction instruction)
		{
			bool flag = matcher.Matches(instruction);
			if (flag)
			{
				*operand = (T)instruction.operand;
			}
			return flag;
		}
	}
	internal static class InstructionUtilities
	{
		public static CodeInstruction MakeLdarg(int index)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			if (index < 256)
			{
				return (CodeInstruction)(index switch
				{
					0 => (object)new CodeInstruction(OpCodes.Ldarg_0, (object)null), 
					1 => (object)new CodeInstruction(OpCodes.Ldarg_1, (object)null), 
					2 => (object)new CodeInstruction(OpCodes.Ldarg_2, (object)null), 
					3 => (object)new CodeInstruction(OpCodes.Ldarg_3, (object)null), 
					_ => (object)new CodeInstruction(OpCodes.Ldarg_S, (object)index), 
				});
			}
			return new CodeInstruction(OpCodes.Ldarg, (object)index);
		}

		public static int PopCount(this CodeInstruction instruction)
		{
			if (instruction.opcode == OpCodes.Call || instruction.opcode == OpCodes.Callvirt || instruction.opcode == OpCodes.Newobj)
			{
				MethodBase methodBase = (MethodBase)instruction.operand;
				int num = methodBase.GetParameters().Length;
				if (!methodBase.IsStatic)
				{
					num++;
				}
				return num;
			}
			if (instruction.opcode == OpCodes.Ret)
			{
				return 1;
			}
			return instruction.opcode.StackBehaviourPop switch
			{
				StackBehaviour.Pop0 => 0, 
				StackBehaviour.Pop1 => 1, 
				StackBehaviour.Pop1_pop1 => 2, 
				StackBehaviour.Popi => 1, 
				StackBehaviour.Popi_pop1 => 2, 
				StackBehaviour.Popi_popi => 2, 
				StackBehaviour.Popi_popi8 => 2, 
				StackBehaviour.Popi_popi_popi => 3, 
				StackBehaviour.Popi_popr4 => 2, 
				StackBehaviour.Popi_popr8 => 2, 
				StackBehaviour.Popref => 1, 
				StackBehaviour.Popref_pop1 => 2, 
				StackBehaviour.Popref_popi => 2, 
				StackBehaviour.Popref_popi_popi => 3, 
				StackBehaviour.Popref_popi_popi8 => 3, 
				StackBehaviour.Popref_popi_popr4 => 3, 
				StackBehaviour.Popref_popi_popr8 => 3, 
				StackBehaviour.Popref_popi_popref => 3, 
				StackBehaviour.Varpop => throw new NotImplementedException($"Variable pop on non-call instruction '{instruction}'"), 
				StackBehaviour.Popref_popi_pop1 => 3, 
				_ => throw new NotSupportedException($"StackBehaviourPop of {instruction.opcode.StackBehaviourPop} was not a pop for instruction '{instruction}'"), 
			};
		}

		public static int PushCount(this CodeInstruction instruction)
		{
			if (instruction.opcode == OpCodes.Call || instruction.opcode == OpCodes.Callvirt || instruction.opcode == OpCodes.Newobj)
			{
				if (instruction.operand is MethodInfo methodInfo && methodInfo.ReturnType == typeof(void))
				{
					return 0;
				}
				return 1;
			}
			return instruction.opcode.StackBehaviourPush switch
			{
				StackBehaviour.Push0 => 0, 
				StackBehaviour.Push1 => 1, 
				StackBehaviour.Push1_push1 => 2, 
				StackBehaviour.Pushi => 1, 
				StackBehaviour.Pushi8 => 1, 
				StackBehaviour.Pushr4 => 1, 
				StackBehaviour.Pushr8 => 1, 
				StackBehaviour.Pushref => 1, 
				StackBehaviour.Varpush => throw new NotImplementedException($"Variable push on non-call instruction '{instruction}'"), 
				_ => throw new NotSupportedException($"StackBehaviourPush of {instruction.opcode.StackBehaviourPush} was not a push for instruction '{instruction}'"), 
			};
		}

		public static int? GetLdargIndex(this CodeInstruction instruction)
		{
			OpCode opcode = instruction.opcode;
			if (opcode == OpCodes.Ldarg_0)
			{
				return 0;
			}
			if (opcode == OpCodes.Ldarg_1)
			{
				return 1;
			}
			if (opcode == OpCodes.Ldarg_2)
			{
				return 2;
			}
			if (opcode == OpCodes.Ldarg_3)
			{
				return 3;
			}
			if (opcode == OpCodes.Ldarg || opcode == OpCodes.Ldarg_S)
			{
				return instruction.operand as int?;
			}
			return null;
		}

		public static int? GetLdlocIndex(this CodeInstruction instruction)
		{
			OpCode opcode = instruction.opcode;
			if (opcode == OpCodes.Ldloc_0)
			{
				return 0;
			}
			if (opcode == OpCodes.Ldloc_1)
			{
				return 1;
			}
			if (opcode == OpCodes.Ldloc_2)
			{
				return 2;
			}
			if (opcode == OpCodes.Ldloc_3)
			{
				return 3;
			}
			if (opcode == OpCodes.Ldloc || opcode == OpCodes.Ldloc_S)
			{
				return (instruction.operand as LocalBuilder)?.LocalIndex;
			}
			return null;
		}

		public static int? GetStlocIndex(this CodeInstruction instruction)
		{
			OpCode opcode = instruction.opcode;
			if (opcode == OpCodes.Stloc_0)
			{
				return 0;
			}
			if (opcode == OpCodes.Stloc_1)
			{
				return 1;
			}
			if (opcode == OpCodes.Stloc_2)
			{
				return 2;
			}
			if (opcode == OpCodes.Stloc_3)
			{
				return 3;
			}
			if (opcode == OpCodes.Stloc || opcode == OpCodes.Stloc_S)
			{
				return (instruction.operand as LocalBuilder)?.LocalIndex;
			}
			return null;
		}

		public static CodeInstruction LdlocToStloc(this CodeInstruction instruction)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			OpCode opcode = instruction.opcode;
			if (opcode == OpCodes.Ldloc_0)
			{
				return new CodeInstruction(OpCodes.Stloc_0, (object)null);
			}
			if (opcode == OpCodes.Ldloc_1)
			{
				return new CodeInstruction(OpCodes.Stloc_1, (object)null);
			}
			if (opcode == OpCodes.Ldloc_2)
			{
				return new CodeInstruction(OpCodes.Stloc_2, (object)null);
			}
			if (opcode == OpCodes.Ldloc_3)
			{
				return new CodeInstruction(OpCodes.Stloc_3, (object)null);
			}
			if (opcode == OpCodes.Ldloc || opcode == OpCodes.Ldloc_S)
			{
				return new CodeInstruction(OpCodes.Stloc, instruction.operand);
			}
			return null;
		}

		public static CodeInstruction StlocToLdloc(this CodeInstruction instruction)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			OpCode opcode = instruction.opcode;
			if (opcode == OpCodes.Stloc_0)
			{
				return new CodeInstruction(OpCodes.Ldloc_0, (object)null);
			}
			if (opcode == OpCodes.Stloc_1)
			{
				return new CodeInstruction(OpCodes.Ldloc_1, (object)null);
			}
			if (opcode == OpCodes.Stloc_2)
			{
				return new CodeInstruction(OpCodes.Ldloc_2, (object)null);
			}
			if (opcode == OpCodes.Stloc_3)
			{
				return new CodeInstruction(OpCodes.Ldloc_3, (object)null);
			}
			if (opcode == OpCodes.Stloc || opcode == OpCodes.Stloc_S)
			{
				return new CodeInstruction(OpCodes.Ldloc, instruction.operand);
			}
			return null;
		}

		public static int? GetLdcI32(this CodeInstruction instruction)
		{
			OpCode opcode = instruction.opcode;
			if (opcode == OpCodes.Ldc_I4_M1)
			{
				return -1;
			}
			if (opcode == OpCodes.Ldc_I4_0)
			{
				return 0;
			}
			if (opcode == OpCodes.Ldc_I4_1)
			{
				return 1;
			}
			if (opcode == OpCodes.Ldc_I4_2)
			{
				return 2;
			}
			if (opcode == OpCodes.Ldc_I4_3)
			{
				return 3;
			}
			if (opcode == OpCodes.Ldc_I4_4)
			{
				return 4;
			}
			if (opcode == OpCodes.Ldc_I4_5)
			{
				return 5;
			}
			if (opcode == OpCodes.Ldc_I4_6)
			{
				return 6;
			}
			if (opcode == OpCodes.Ldc_I4_7)
			{
				return 7;
			}
			if (opcode == OpCodes.Ldc_I4_8)
			{
				return 8;
			}
			if (opcode == OpCodes.Ldc_I4_S)
			{
				return instruction.operand as sbyte?;
			}
			if (opcode == OpCodes.Ldc_I4)
			{
				return instruction.operand as int?;
			}
			return null;
		}
	}
	public static class ReflectionExtensions
	{
		public static MethodInfo GetGenericMethod(this Type type, string name, Type[] parameters, Type[] genericArgs)
		{
			MethodInfo[] methods = type.GetMethods();
			MethodInfo[] array = methods;
			foreach (MethodInfo methodInfo in array)
			{
				if (!(methodInfo.Name != name) && methodInfo.IsGenericMethodDefinition)
				{
					return methodInfo.MakeGenericMethod(genericArgs);
				}
			}
			return null;
		}
	}
}
namespace LobbyControl.TerminalCommands
{
	public class Command
	{
		public TerminalNode previousTerminalNode;

		public bool awaitingConfirmation
		{
			get
			{
				return CommandManager.awaitingConfirmationCommand == this;
			}
			set
			{
				CommandManager.awaitingConfirmationCommand = (value ? this : null);
			}
		}

		public virtual bool IsCommand(string[] args)
		{
			return false;
		}

		public virtual TerminalNode Execute(string[] args)
		{
			return TerminalPatch.CreateTerminalNode("Execute override was not found.\n\n");
		}

		public virtual TerminalNode ExecuteConfirmation(string[] args)
		{
			string text = args[0].ToLower();
			if ("confirm".Contains(text) && text.Length > 0)
			{
				return OnConfirm(args);
			}
			if ("deny".Contains(text) && text.Length > 0)
			{
				return OnDeny(args);
			}
			return OnInvalidInput(args);
		}

		protected virtual TerminalNode OnConfirm(string[] args)
		{
			return TerminalPatch.CreateTerminalNode("OnConfirm override was not found.\n\n");
		}

		protected virtual TerminalNode OnDeny(string[] args)
		{
			return TerminalPatch.CreateTerminalNode("OnDeny override was not found.\n\n");
		}

		protected virtual TerminalNode OnInvalidInput(string[] args)
		{
			return previousTerminalNode;
		}
	}
	internal class CommandManager
	{
		private static List<Command> commands = new List<Command>();

		public static Command awaitingConfirmationCommand;

		public static void Initialize()
		{
			commands = new List<Command>
			{
				new LobbyCommand()
			};
			awaitingConfirmationCommand = null;
		}

		public static bool TryExecuteCommand(string[] array, out TerminalNode terminalNode)
		{
			terminalNode = null;
			if (awaitingConfirmationCommand != null)
			{
				Command command = awaitingConfirmationCommand;
				terminalNode = command.ExecuteConfirmation(array);
				command.previousTerminalNode = terminalNode;
				return true;
			}
			Command command2 = GetCommand(array);
			if (command2 == null)
			{
				return false;
			}
			terminalNode = command2.Execute(array);
			command2.previousTerminalNode = terminalNode;
			return true;
		}

		public static void OnLocalDisconnect()
		{
			awaitingConfirmationCommand = null;
		}

		public static void OnTerminalQuit()
		{
			awaitingConfirmationCommand = null;
		}

		private static Command GetCommand(string[] args)
		{
			Command result = null;
			commands.ForEach(delegate(Command command)
			{
				if (result == null && command.IsCommand(args))
				{
					result = command;
				}
			});
			return result;
		}
	}
	public class LobbyCommand : Command
	{
		private const string DefaultText = "- status        : prints the current lobby status\r\n\r\nSteam:\r\n- open          : open the lobby\r\n- close         : close the lobby\r\n- private       : set lobby to Invite Only\r\n- friend        : set lobby to Friends Only\r\n- public        : set lobby to Public\r\n- rename [name] : change the name of the lobby\r\n\r\nSaving:\r\n- autosave      : toggle autosave for the savefile\r\n- save (name)   : save the lobby\r\n- load (name)   : load a savefile\r\n- switch (name) : swap savefile without loading it\r\n- clear         : reset the current lobby to empty\r\n\r\nExtra:\r\n- dropall       : drop all items to the ground\r\n";

		private const string DefaultTextLAN = "- status        : prints the current lobby status\r\n\r\nLAN:\r\n- open          : set the lobby to be discoverable\r\n- close         : set the lobby to be non-discoverable\r\n- rename [name] : change the name of the lobby\r\n\r\nSaving:\r\n- autosave      : toggle autosave for the savefile\r\n- save (name)   : save the lobby\r\n- load (name)   : load a savefile\r\n- switch (name) : swap savefile without loading it\r\n- clear         : reset the current lobby to empty\r\n\r\nExtra:\r\n- dropall       : drop all items to the ground\r\n";

		private static uint? _returnUnlockableFromStorageServerRpcID;

		private static uint? _onPlayerConnectedClientRpcID;

		public override bool IsCommand(string[] args)
		{
			if (GameNetworkManager.Instance.isHostingGame)
			{
				return args[0].Trim().ToLower() == "lobby";
			}
			return false;
		}

		public override TerminalNode Execute(string[] args)
		{
			TerminalNode node = ScriptableObject.CreateInstance<TerminalNode>();
			try
			{
				if (Utility.IsNullOrWhiteSpace(args[1]))
				{
					return HelpNode();
				}
				switch (args[1])
				{
				case "status":
					StatusCommand(ref node, args);
					break;
				case "open":
				{
					if (PerformOrbitCheck(node, out var errorText10))
					{
						return errorText10;
					}
					if (!LobbyControl.CanModifyLobby)
					{
						node.displayText = "Lobby cannot be changed at the moment\n\n";
					}
					else
					{
						OpenCommand(ref node, args);
					}
					break;
				}
				case "close":
				{
					if (PerformOrbitCheck(node, out var errorText7))
					{
						return errorText7;
					}
					if (!LobbyControl.CanModifyLobby)
					{
						node.displayText = "Lobby cannot be changed at the moment\n\n";
					}
					else
					{
						CloseCommand(ref node, args);
					}
					break;
				}
				case "private":
				{
					if (PerformOrbitCheck(node, out var errorText3))
					{
						return errorText3;
					}
					if (!LobbyControl.CanModifyLobby)
					{
						node.displayText = "Lobby cannot be changed at the moment\n\n";
					}
					else
					{
						PrivateCommand(ref node, args);
					}
					break;
				}
				case "friend":
				{
					if (PerformOrbitCheck(node, out var errorText11))
					{
						return errorText11;
					}
					if (!LobbyControl.CanModifyLobby)
					{
						node.displayText = "Lobby cannot be changed at the moment\n\n";
					}
					else
					{
						FriendCommand(ref node, args);
					}
					break;
				}
				case "public":
				{
					if (PerformOrbitCheck(node, out var errorText2))
					{
						return errorText2;
					}
					if (!LobbyControl.CanModifyLobby)
					{
						node.displayText = "Lobby cannot be changed at the moment\n\n";
					}
					else
					{
						PublicCommand(ref node, args);
					}
					break;
				}
				case "rename":
				{
					if (PerformOrbitCheck(node, out var errorText6))
					{
						return errorText6;
					}
					if (!LobbyControl.CanModifyLobby)
					{
						node.displayText = "Lobby cannot be changed at the moment\n\n";
					}
					else
					{
						RenameCommand(ref node, args);
					}
					break;
				}
				case "autosave":
					AutoSaveCommand(ref node, args);
					break;
				case "save":
				{
					if (PerformOrbitCheck(node, out var errorText8))
					{
						return errorText8;
					}
					if (!LobbyControl.CanModifyLobby)
					{
						node.displayText = "Lobby cannot be changed at the moment\n\n";
					}
					else
					{
						SaveCommand(ref node, args);
					}
					break;
				}
				case "load":
				{
					if (PerformOrbitCheck(node, out var errorText4))
					{
						return errorText4;
					}
					if (!LobbyControl.CanModifyLobby)
					{
						node.displayText = "Lobby cannot be changed at the moment\n\n";
					}
					else
					{
						LoadCommand(ref node, args);
					}
					break;
				}
				case "switch":
				{
					if (PerformOrbitCheck(node, out var errorText9))
					{
						return errorText9;
					}
					if (!LobbyControl.CanModifyLobby)
					{
						node.displayText = "Lobby cannot be changed at the moment\n\n";
					}
					else
					{
						SwitchCommand(ref node, args);
					}
					break;
				}
				case "clear":
				{
					if (PerformOrbitCheck(node, out var errorText5))
					{
						return errorText5;
					}
					if (!LobbyControl.CanModifyLobby)
					{
						node.displayText = "Lobby cannot be changed at the moment\n\n";
					}
					else
					{
						ClearCommand(ref node, args);
					}
					break;
				}
				case "dropall":
				{
					if (PerformOrbitCheck(node, out var errorText))
					{
						return errorText;
					}
					if (!LobbyControl.CanModifyLobby)
					{
						node.displayText = "Lobby cannot be changed at the moment\n\n";
					}
					else
					{
						DropAllCommand(ref node, args);
					}
					break;
				}
				case "help":
					node = HelpNode();
					break;
				default:
					node = HelpNode();
					node.displayText = "Invalid Command, options:\n" + node.displayText;
					break;
				}
			}
			catch (Exception ex)
			{
				LobbyControl.Log.LogError((object)("Exception:\n\n" + ex));
				node.displayText = "Exception!\n\n";
			}
			return node;
		}

		private static bool StatusCommand(ref TerminalNode node, string[] args)
		{
			//IL_017e: 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_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			StringBuilder stringBuilder;
			if (args.Length > 2 && args[2].ToLower().Equals("queue"))
			{
				stringBuilder = new StringBuilder("Lobby Queue Status:");
				if (JoinQueuePatches.ConnectingClient != null)
				{
					stringBuilder.Append("\n┬ Connecting client is '").Append(JoinQueuePatches.ConnectingClient.Name).Append("'");
					stringBuilder.Append("\n└ Remaining time: ").Append(JoinQueuePatches.ConnectionTimer.Remaining.TotalMilliseconds).Append(" ms");
				}
				else
				{
					stringBuilder.Append("\n─ No client is currently connecting");
				}
				stringBuilder.Append("\n┬ Queued clients: ").Append(JoinQueuePatches.ConnectionQueue.Count);
				foreach (JoinQueuePatches.ConnectionQueueEntry item in JoinQueuePatches.ConnectionQueue.Take(7))
				{
					stringBuilder.Append("\n├ ").Append(item.Name);
				}
				stringBuilder.Append("\n└ [...]");
			}
			else
			{
				GameNetworkManager instance = GameNetworkManager.Instance;
				bool flag = false;
				string value = instance.steamLobbyName;
				string value2;
				if (instance.disableSteam)
				{
					UnityTransport component = ((Component)NetworkManager.Singleton).GetComponent<UnityTransport>();
					value2 = ((component.ConnectionData.ServerListenAddress == "0.0.0.0") ? "Public" : "Private");
				}
				else
				{
					if (!instance.currentLobby.HasValue)
					{
						node.displayText = "Failed to fetch lobby ( was null )\n\n";
						return false;
					}
					Lobby value3 = instance.currentLobby.Value;
					flag = LobbyPatcher.IsOpen(value3);
					value2 = ((object)LobbyPatcher.GetVisibility(value3)/*cast due to .constrained prefix*/).ToString();
					value = ((Lobby)(ref value3)).GetData("name");
				}
				bool canSave = LobbyControl.CanSave;
				stringBuilder = new StringBuilder("Lobby Status:");
				stringBuilder.Append("\n- File is '").Append(instance.currentSaveFileName).Append("'");
				stringBuilder.Append("\n- Name is '").Append(value).Append("'");
				if (!instance.disableSteam)
				{
					stringBuilder.Append("\n- Status is ").Append(flag ? "Open" : "Closed");
				}
				stringBuilder.Append("\n- Visibility is ").Append(value2);
				stringBuilder.Append("\n- Saving is ").Append(canSave ? "Automatic" : "Manual");
				if (PluginConfig.JoinQueue.Enabled.Value)
				{
					stringBuilder.Append("\n");
					stringBuilder.Append("\n- ").Append(JoinQueuePatches.QueuedClients).Append(" Players are waiting in queue");
					stringBuilder.Append("\n Type 'lobby status queue' for more details");
				}
			}
			stringBuilder.Append("\n\n");
			node.displayText = stringBuilder.ToString();
			node.maxCharactersToType = node.displayText.Length + 2;
			return true;
		}

		private static bool OpenCommand(ref TerminalNode node, string[] args)
		{
			LobbyControl.Log.LogDebug((object)"Reopening lobby, setting to joinable.");
			GameNetworkManager instance = GameNetworkManager.Instance;
			if (instance.disableSteam)
			{
				UnityTransport component = ((Component)NetworkManager.Singleton).GetComponent<UnityTransport>();
				if (component.ConnectionData.ServerListenAddress != "0.0.0.0")
				{
					node.displayText = "Server is limited to local connections\n\n";
					return false;
				}
				instance.lobbyHostSettings.isLobbyPublic = true;
				ES3.Save<bool>("HostSettings_Public", instance.lobbyHostSettings.isLobbyPublic, "LCGeneralSaveData");
			}
			else if (!instance.currentLobby.HasValue)
			{
				node.displayText = "Failed to fetch lobby ( was null )\n\n";
				return false;
			}
			instance.SetLobbyJoinable(true);
			Object.FindObjectOfType<QuickMenuManager>().inviteFriendsTextAlpha.alpha = 1f;
			string text = "Lobby is now Open";
			LobbyControl.Log.LogInfo((object)text);
			node.displayText = text + "\n\n";
			node.maxCharactersToType = node.displayText.Length + 2;
			return true;
		}

		private static bool CloseCommand(ref TerminalNode node, string[] args)
		{
			LobbyControl.Log.LogDebug((object)"Closing lobby, setting to not joinable.");
			GameNetworkManager instance = GameNetworkManager.Instance;
			if (instance.disableSteam)
			{
				UnityTransport component = ((Component)NetworkManager.Singleton).GetComponent<UnityTransport>();
				if (component.ConnectionData.ServerListenAddress != "0.0.0.0")
				{
					node.displayText = "Server is limited to local connections\n\n";
					return false;
				}
				instance.lobbyHostSettings.isLobbyPublic = false;
				ES3.Save<bool>("HostSettings_Public", instance.lobbyHostSettings.isLobbyPublic, "LCGeneralSaveData");
			}
			else if (!instance.currentLobby.HasValue)
			{
				node.displayText = "Failed to fetch lobby ( was null )\n\n";
				return false;
			}
			instance.SetLobbyJoinable(false);
			Object.FindObjectOfType<QuickMenuManager>().inviteFriendsTextAlpha.alpha = 0f;
			string text = "Lobby is now Closed";
			LobbyControl.Log.LogInfo((object)text);
			node.displayText = text + "\n\n";
			node.maxCharactersToType = node.displayText.Length + 2;
			return true;
		}

		private static bool PrivateCommand(ref TerminalNode node, string[] args)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			LobbyControl.Log.LogDebug((object)"Locking lobby, setting to Private.");
			GameNetworkManager instance = GameNetworkManager.Instance;
			if (!instance.currentLobby.HasValue)
			{
				node.displayText = "Failed to fetch lobby ( was null )\n\n";
				return false;
			}
			ES3.Save<bool>("HostSettings_Public", false, "LCGeneralSaveData");
			Lobby value = instance.currentLobby.Value;
			((Lobby)(ref value)).SetPrivate();
			string text = "Lobby is now Private";
			LobbyControl.Log.LogInfo((object)text);
			node.displayText = text + "\n\n";
			node.maxCharactersToType = node.displayText.Length + 2;
			return true;
		}

		private static bool FriendCommand(ref TerminalNode node, string[] args)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			LobbyControl.Log.LogDebug((object)"Locking lobby, setting to Friends Only.");
			GameNetworkManager instance = GameNetworkManager.Instance;
			if (!instance.currentLobby.HasValue)
			{
				node.displayText = "Failed to fetch lobby ( was null )\n\n";
				return false;
			}
			ES3.Save<bool>("HostSettings_Public", false, "LCGeneralSaveData");
			Lobby value = instance.currentLobby.Value;
			((Lobby)(ref value)).SetFriendsOnly();
			string text = "Lobby is now Friends Only";
			LobbyControl.Log.LogInfo((object)text);
			node.displayText = text + "\n\n";
			node.maxCharactersToType = node.displayText.Length + 2;
			return true;
		}

		private static bool PublicCommand(ref TerminalNode node, string[] args)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			LobbyControl.Log.LogDebug((object)"Unlocking lobby, setting to Public.");
			GameNetworkManager instance = GameNetworkManager.Instance;
			if (!instance.currentLobby.HasValue)
			{
				node.displayText = "Failed to fetch lobby ( was null )\n\n";
				return false;
			}
			ES3.Save<bool>("HostSettings_Public", true, "LCGeneralSaveData");
			Lobby value = instance.currentLobby.Value;
			((Lobby)(ref value)).SetPublic();
			string text = "Lobby is now Public";
			LobbyControl.Log.LogInfo((object)text);
			node.displayText = text + "\n\n";
			node.maxCharactersToType = node.displayText.Length + 2;
			return true;
		}

		private static bool RenameCommand(ref TerminalNode node, string[] args)
		{
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			if (Utility.IsNullOrWhiteSpace(args[2]))
			{
				node.displayText = "Lobby name cannot be null\n\n";
				return false;
			}
			string text = args[2];
			if (text.Length > 40)
			{
				text = text.Substring(0, 40);
			}
			LobbyControl.Log.LogDebug((object)("Renaming lobby: \"" + text + "\""));
			GameNetworkManager instance = GameNetworkManager.Instance;
			if (!instance.disableSteam && !instance.currentLobby.HasValue)
			{
				node.displayText = "Failed to fetch lobby ( was null )\n\n";
				return false;
			}
			instance.lobbyHostSettings.lobbyName = text;
			instance.steamLobbyName = instance.lobbyHostSettings.lobbyName;
			if (instance.currentLobby.HasValue)
			{
				Lobby value = instance.currentLobby.Value;
				((Lobby)(ref value)).SetData("name", instance.steamLobbyName);
			}
			ES3.Save<string>("HostSettings_Name", instance.steamLobbyName, "LCGeneralSaveData");
			string text2 = "Lobby renamed to \"" + text + "\"";
			LobbyControl.Log.LogInfo((object)text2);
			node.displayText = text2 + "\n\n";
			node.maxCharactersToType = node.displayText.Length + 2;
			return true;
		}

		private static bool AutoSaveCommand(ref TerminalNode node, string[] args)
		{
			LobbyControl.Log.LogDebug((object)"Toggling AutoSave");
			LobbyControl.CanSave = (LobbyControl.AutoSaveEnabled = !LobbyControl.AutoSaveEnabled);
			string text = "AutoSaving is now " + (LobbyControl.CanSave ? "On" : "Off");
			LobbyControl.Log.LogInfo((object)text);
			node.displayText = text + "\n\n";
			node.maxCharactersToType = node.displayText.Length + 2;
			return true;
		}

		private static bool SaveCommand(ref TerminalNode node, string[] args)
		{
			if (StartOfRound.Instance.isChallengeFile)
			{
				node.displayText = "Cannot Edit Challenge Save\n\n";
				return false;
			}
			LobbyControl.Log.LogDebug((object)"Saving Lobby");
			GameNetworkManager instance = GameNetworkManager.Instance;
			string currentSaveFileName = instance.currentSaveFileName;
			if (!Utility.IsNullOrWhiteSpace(args[2]))
			{
				string text = args[2];
				if (text.Length > 20)
				{
					text = text.Substring(0, 20);
				}
				instance.currentSaveFileName = text;
			}
			if (currentSaveFileName != instance.currentSaveFileName)
			{
				ES3.CopyFile(currentSaveFileName, instance.currentSaveFileName);
			}
			LobbyControl.CanSave = true;
			HUDManager.Instance.saveDataIconAnimatorB.SetTrigger("save");
			instance.SaveGameValues();
			string text2 = "Lobby Saved to " + instance.currentSaveFileName;
			LobbyControl.CanSave = LobbyControl.AutoSaveEnabled;
			instance.currentSaveFileName = currentSaveFileName;
			LobbyControl.Log.LogInfo((object)text2);
			node.displayText = text2 + "\n\n";
			node.maxCharactersToType = node.displayText.Length + 2;
			return true;
		}

		private static bool LoadCommand(ref TerminalNode node, string[] args)
		{
			if (StartOfRound.Instance.isChallengeFile)
			{
				node.displayText = "Cannot Edit Challenge Save\n\n";
				return false;
			}
			LobbyControl.Log.LogDebug((object)"Reloading Lobby");
			GameNetworkManager instance = GameNetworkManager.Instance;
			if (!Utility.IsNullOrWhiteSpace(args[2]))
			{
				string text = args[2];
				if (text.Length > 20)
				{
					text = text.Substring(0, 20);
				}
				instance.currentSaveFileName = text;
			}
			string text2 = "Lobby '" + instance.currentSaveFileName + "' loaded";
			((MonoBehaviour)StartOfRound.Instance).StartCoroutine(LoadLobbyCoroutine());
			LobbyControl.AutoSaveEnabled = (LobbyControl.CanSave = ES3.Load<bool>("LC_SavingMethod", GameNetworkManager.Instance.currentSaveFileName, true));
			LobbyControl.Log.LogInfo((object)text2);
			node.displayText = text2 + "\n\n";
			node.maxCharactersToType = node.displayText.Length + 2;
			return true;
		}

		private static bool SwitchCommand(ref TerminalNode node, string[] args)
		{
			if (StartOfRound.Instance.isChallengeFile)
			{
				node.displayText = "Cannot Edit Challenge Save\n\n";
				return false;
			}
			LobbyControl.Log.LogDebug((object)"Switching Lobby");
			GameNetworkManager instance = GameNetworkManager.Instance;
			if (Utility.IsNullOrWhiteSpace(args[2]))
			{
				node.displayText = "You need to specify a destination for the swap!";
				return false;
			}
			string text = args[2];
			if (text.Length > 20)
			{
				text = text.Substring(0, 20);
			}
			instance.currentSaveFileName = text;
			string text2 = "Lobby is now saving to '" + instance.currentSaveFileName + "'";
			node.displayText = text2 + "\n\n";
			node.maxCharactersToType = node.displayText.Length + 2;
			return true;
		}

		private static bool ClearCommand(ref TerminalNode node, string[] args)
		{
			if (StartOfRound.Instance.isChallengeFile)
			{
				node.displayText = "Cannot Edit Challenge Save\n\n";
				return false;
			}
			LobbyControl.Log.LogDebug((object)"Clearing Lobby");
			LobbyControl.CanSave = true;
			GameNetworkManager.Instance.ResetSavedGameValues();
			ES3.DeleteFile(GameNetworkManager.Instance.currentSaveFileName);
			LobbyControl.CanSave = LobbyControl.AutoSaveEnabled;
			bool flag = LoadCommand(ref node, new string[3]);
			if (flag)
			{
				node.displayText = "Lobby is now Empty!";
			}
			return flag;
		}

		private static bool DropAllCommand(ref TerminalNode node, string[] args)
		{
			LobbyControl.Log.LogDebug((object)"Dropping all Items");
			string text = "All Items Dropped";
			PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
			foreach (PlayerControllerB val in allPlayerScripts)
			{
				val.DropAllHeldItemsAndSyncNonexact();
			}
			node.displayText = text + "\n\n";
			node.maxCharactersToType = node.displayText.Length + 2;
			return true;
		}

		private static bool PerformOrbitCheck(TerminalNode terminalNode, out TerminalNode errorText)
		{
			if (!StartOfRound.Instance.inShipPhase)
			{
				terminalNode.displayText = "Can only be used while in Orbit\n\n";
				errorText = terminalNode;
				return true;
			}
			errorText = null;
			return false;
		}

		private static TerminalNode HelpNode()
		{
			TerminalNode val = ScriptableObject.CreateInstance<TerminalNode>();
			val.displayText = (GameNetworkManager.Instance.disableSteam ? "- status        : prints the current lobby status\r\n\r\nLAN:\r\n- open          : set the lobby to be discoverable\r\n- close         : set the lobby to be non-discoverable\r\n- rename [name] : change the name of the lobby\r\n\r\nSaving:\r\n- autosave      : toggle autosave for the savefile\r\n- save (name)   : save the lobby\r\n- load (name)   : load a savefile\r\n- switch (name) : swap savefile without loading it\r\n- clear         : reset the current lobby to empty\r\n\r\nExtra:\r\n- dropall       : drop all items to the ground\r\n" : "- status        : prints the current lobby status\r\n\r\nSteam:\r\n- open          : open the lobby\r\n- close         : close the lobby\r\n- private       : set lobby to Invite Only\r\n- friend        : set lobby to Friends Only\r\n- public        : set lobby to Public\r\n- rename [name] : change the name of the lobby\r\n\r\nSaving:\r\n- autosave      : toggle autosave for the savefile\r\n- save (name)   : save the lobby\r\n- load (name)   : load a savefile\r\n- switch (name) : swap savefile without loading it\r\n- clear         : reset the current lobby to empty\r\n\r\nExtra:\r\n- dropall       : drop all items to the ground\r\n");
			val.clearPreviousText = true;
			val.maxCharactersToType = val.displayText.Length + 2;
			return val;
		}

		private static IEnumerator LoadLobbyCoroutine()
		{
			StartOfRound startOfRound = StartOfRound.Instance;
			Terminal terminal = Object.FindObjectOfType<Terminal>();
			startOfRound.ResetShip();
			VehicleController[] array = Object.FindObjectsOfType<VehicleController>();
			VehicleController[] array2 = array;
			foreach (VehicleController val in array2)
			{
				if ((Object)(object)((NetworkBehaviour)val).NetworkObject != (Object)null)
				{
					((NetworkBehaviour)val).NetworkObject.Despawn(false);
				}
			}
			bool mem = GameNetworkManager.Instance.gameHasStarted;
			GameNetworkManager.Instance.gameHasStarted = false;
			foreach (KeyValuePair<int, GameObject> item in StartOfRound.Instance.SpawnedShipUnlockables.ToList())
			{
				UnlockableItem val2 = startOfRound.unlockablesList.unlockables[item.Key];
				if (val2.alreadyUnlocked && val2.spawnPrefab && !((Object)(object)item.Value == (Object)null))
				{
					NetworkObject component = item.Value.GetComponent<NetworkObject>();
					if ((Object)(object)component != (Object)null && component.IsSpawned)
					{
						component.Despawn(true);
					}
				}
			}
			startOfRound.SpawnedShipUnlockables.Clear();
			startOfRound.suitsPlaced = 0;
			GameNetworkManager.Instance.ResetUnlockablesListValues(false);
			yield return (object)new WaitForSeconds(0.2f);
			startOfRound.SetTimeAndPlanetToSavedSettings();
			startOfRound.SetMapScreenInfoToCurrentLevel();
			terminal.Start();
			if (startOfRound.connectedPlayersAmount >= 1)
			{
				RefreshLobby();
			}
			ReloadUnlockables();
			yield return (object)new WaitForSeconds(0.2f);
			startOfRound.LoadAttachedVehicle();
			yield return (object)new WaitForSeconds(0.1f);
			startOfRound.LoadShipGrabbableItems();
			yield return (object)new WaitForSeconds(0.1f);
			if (startOfRound.connectedPlayersAmount >= 1)
			{
				startOfRound.SyncShipUnlockablesServerRpc();
			}
			GameNetworkManager.Instance.gameHasStarted = mem;
		}

		private static void ReloadUnlockables()
		{
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: 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_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ce: 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_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0264: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: 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_00f1: 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_00f8: 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)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: 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_0112: 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_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: 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_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: 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_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0314: Unknown result type (might be due to invalid IL or missing references)
			//IL_0317: Unknown result type (might be due to invalid IL or missing references)
			//IL_031c: Unknown result type (might be due to invalid IL or missing references)
			//IL_031e: Unknown result type (might be due to invalid IL or missing references)
			//IL_032c: Unknown result type (might be due to invalid IL or missing references)
			StartOfRound instance = StartOfRound.Instance;
			instance.LoadUnlockables();
			try
			{
				for (int i = 0; i < instance.unlockablesList.unlockables.Count; i++)
				{
					UnlockableItem val = instance.unlockablesList.unlockables[i];
					if (val.unlockableType == 0 || !val.alreadyUnlocked)
					{
						continue;
					}
					LobbyControl.Log.LogDebug((object)(val.unlockableName + " starting"));
					if (!instance.SpawnedShipUnlockables.ContainsKey(i))
					{
						instance.SpawnUnlockable(i, true);
					}
					PlaceableShipObject val2 = instance.SpawnedShipUnlockables[i].GetComponent<PlaceableShipObject>();
					if (val2 == null)
					{
						val2 = instance.SpawnedShipUnlockables[i].GetComponentInChildren<PlaceableShipObject>();
					}
					if (val2 != null)
					{
						LobbyControl.Log.LogDebug((object)(val.unlockableName + " continuing"));
						Quaternion val4;
						if (Object.op_Implicit((Object)(object)val2.parentObjectSecondary))
						{
							Quaternion rotation = ((Component)val2.parentObjectSecondary).transform.rotation;
							Quaternion rotation2 = ((Component)val2.parentObjectSecondary).transform.rotation;
							Quaternion rotation3 = ((Component)val2.mainMesh).transform.rotation;
							Quaternion val3 = rotation * Quaternion.Inverse(rotation2);
							val4 = val3 * rotation3;
							val.placedRotation = ((Quaternion)(ref val4)).eulerAngles;
							Vector3 position = val2.parentObjectSecondary.position;
							Vector3 val5 = ((Component)val2.parentObjectSecondary).transform.position - ((Component)val2.mainMesh).transform.position;
							Vector3 val6 = ((Component)val2.mainMesh).transform.position - ((Component)val2.placeObjectCollider).transform.position;
							val.placedPosition = position - val5 - val6;
						}
						else
						{
							Quaternion val7 = Quaternion.Euler(val2.parentObject.rotationOffset);
							Quaternion rotation4 = ((Component)val2.parentObject).transform.rotation;
							Quaternion rotation5 = ((Component)val2.mainMesh).transform.rotation;
							Quaternion val8 = val7 * Quaternion.Inverse(rotation4);
							val4 = val8 * rotation5;
							val.placedRotation = ((Quaternion)(ref val4)).eulerAngles;
							Vector3 val9 = ((Component)val2.parentObject).transform.position - ((Component)val2.mainMesh).transform.position;
							Vector3 val10 = ((Component)val2.mainMesh).transform.position - ((Component)val2.placeObjectCollider).transform.position;
							val.placedPosition = StartOfRound.Instance.elevatorTransform.TransformPoint(val2.parentObject.positionOffset) - val9 - val10;
						}
					}
				}
				if (instance.connectedPlayersAmount < 1)
				{
					return;
				}
				List<ulong> targetClientIds = instance.ClientPlayerList.Keys.ToList();
				ClientRpcParams val11 = new ClientRpcParams
				{
					Send = new ClientRpcSendParams
					{
						TargetClientIds = targetClientIds
					}
				};
				for (int j = 0; j < instance.unlockablesList.unlockables.Count; j++)
				{
					UnlockableItem val12 = instance.unlockablesList.unlockables[j];
					if (val12.alreadyUnlocked && !val12.inStorage && _returnUnlockableFromStorageServerRpcID.HasValue)
					{
						uint value = _returnUnlockableFromStorageServerRpcID.Value;
						FastBufferWriter val13 = ((NetworkBehaviour)instance).__beginSendClientRpc(value, val11, (RpcDelivery)0);
						BytePacker.WriteValueBitPacked(val13, j);
						((NetworkBehaviour)instance).__endSendClientRpc(ref val13, value, val11, (RpcDelivery)0);
					}
				}
				instance.SyncShipUnlockablesServerRpc();
			}
			catch (Exception ex)
			{
				LobbyControl.Log.LogError((object)ex);
			}
		}

		private static void RefreshLobby()
		{
			//IL_0082: 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_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: 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_0116: 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)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: 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_0152: 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_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: 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_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			StartOfRound instance = StartOfRound.Instance;
			List<ulong> list = new List<ulong>();
			List<ulong> list2 = new List<ulong>();
			for (int i = 0; i < instance.allPlayerObjects.Length; i++)
			{
				NetworkObject component = instance.allPlayerObjects[i].GetComponent<NetworkObject>();
				if (!component.IsOwnedByServer)
				{
					list.Add(component.OwnerClientId);
					list2.Add(component.OwnerClientId);
				}
				else if (i == 0)
				{
					list.Add(NetworkManager.Singleton.LocalClientId);
				}
				else
				{
					list.Add(999uL);
				}
			}
			ClientRpcParams val = new ClientRpcParams
			{
				Send = new ClientRpcSendParams
				{
					TargetClientIds = list2
				}
			};
			int groupCredits = Object.FindObjectOfType<Terminal>().groupCredits;
			int profitQuota = TimeOfDay.Instance.profitQuota;
			int quotaFulfilled = TimeOfDay.Instance.quotaFulfilled;
			int num = (int)TimeOfDay.Instance.timeUntilDeadline;
			PlayerControllerB localPlayerController = StartOfRound.Instance.localPlayerController;
			if (_onPlayerConnectedClientRpcID.HasValue)
			{
				uint value = _onPlayerConnectedClientRpcID.Value;
				FastBufferWriter val2 = ((NetworkBehaviour)instance).__beginSendClientRpc(value, val, (RpcDelivery)0);
				BytePacker.WriteValueBitPacked(val2, localPlayerController.actualClientId);
				BytePacker.WriteValueBitPacked(val2, instance.connectedPlayersAmount - 1);
				bool flag = true;
				((FastBufferWriter)(ref val2)).WriteValueSafe<bool>(ref flag, default(ForPrimitives));
				((FastBufferWriter)(ref val2)).WriteValueSafe<ulong>(list.ToArray(), default(ForPrimitives));
				BytePacker.WriteValueBitPacked(val2, instance.ClientPlayerList[localPlayerController.actualClientId]);
				BytePacker.WriteValueBitPacked(val2, groupCredits);
				BytePacker.WriteValueBitPacked(val2, instance.currentLevelID);
				BytePacker.WriteValueBitPacked(val2, profitQuota);
				BytePacker.WriteValueBitPacked(val2, num);
				BytePacker.WriteValueBitPacked(val2, quotaFulfilled);
				BytePacker.WriteValueBitPacked(val2, instance.randomMapSeed);
				((FastBufferWriter)(ref val2)).WriteValueSafe<bool>(ref instance.isChallengeFile, default(ForPrimitives));
				((NetworkBehaviour)instance).__endSendClientRpc(ref val2, value, val, (RpcDelivery)0);
			}
		}

		internal static void Init()
		{
			MethodInfo methodInfo = AccessTools.Method(typeof(StartOfRound), "ReturnUnlockableFromStorageClientRpc", (Type[])null, (Type[])null);
			if (RPCUtils.TryGetRpcID(methodInfo, out var rpcID))
			{
				_returnUnlockableFromStorageServerRpcID = rpcID;
			}
			MethodInfo methodInfo2 = AccessTools.Method(typeof(StartOfRound), "OnPlayerConnectedClientRpc", (Type[])null, (Type[])null);
			if (RPCUtils.TryGetRpcID(methodInfo2, out var rpcID2))
			{
				_onPlayerConnectedClientRpcID = rpcID2;
			}
		}
	}
}
namespace LobbyControl.PopUp
{
	[HarmonyPatch]
	public class PopUpPatch
	{
		public static readonly List<(string objectName, string text)> PopUps = new List<(string, string)>();

		[HarmonyPrefix]
		[HarmonyPatch(typeof(MenuManager), "Awake")]
		private static void AddPopups(MenuManager __instance)
		{
			foreach (var (objectName, text) in PopUps)
			{
				AppendPopup(objectName, text);
			}
		}

		private static void AppendPopup(string objectName, string text)
		{
			GameObject val = GameObject.Find("/Canvas/MenuContainer/");
			GameObject val2 = GameObject.Find("Canvas/MenuContainer/LANWarning/");
			if (!((Object)(object)val2 == (Object)null))
			{
				GameObject val3 = Object.Instantiate<GameObject>(val2, val.transform);
				((Object)val3).name = objectName;
				val3.SetActive(true);
				Transform val4 = val3.transform.Find("Panel/NotificationText");
				TextMeshProUGUI component = ((Component)val4).GetComponent<TextMeshProUGUI>();
				((TMP_Text)component).text = text;
			}
		}
	}
}
namespace LobbyControl.Patches
{
	[HarmonyPatch]
	public static class FacepunchTransportPatches
	{
		internal static readonly Dictionary<ulong, (Connection connection, ConnectionInfo connectionInfo)> Connections = new Dictionary<ulong, (Connection, ConnectionInfo)>();

		[HarmonyPrefix]
		[HarmonyPatch(typeof(FacepunchTransport), "Steamworks.ISocketManager.OnConnected")]
		private static void TrackNewConnection(FacepunchTransport __instance, Connection connection, ConnectionInfo info)
		{
			//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_0036: Unknown result type (might be due to invalid IL or missing references)
			Connections[((Connection)(ref connection)).Id] = (connection, info);
			LobbyControl.Log.LogDebug((object)$"(FacepunchTransport) New connection: {((Connection)(ref connection)).Id} from SteamID {((NetIdentity)(ref info.identity)).SteamId}");
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(FacepunchTransport), "Steamworks.ISocketManager.OnDisconnected")]
		private static void TrackDisconnection(FacepunchTransport __instance, Connection connection, ConnectionInfo info)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			Connections.Remove(((Connection)(ref connection)).Id);
			LobbyControl.Log.LogDebug((object)$"(FacepunchTransport) Disconnected: {((Connection)(ref connection)).Id} at SteamID {((NetIdentity)(ref info.identity)).SteamId}");
		}

		internal static bool TryGetConnection(ulong connectionId, out (Connection connection, ConnectionInfo connectionInfo) connection)
		{
			ulong key = NetworkManager.Singleton.ConnectionManager.ClientIdToTransportId(connectionId);
			return Connections.TryGetValue(key, out connection);
		}
	}
	[HarmonyPatch]
	internal class JoinQueuePatches
	{
		public class ConnectionQueueEntry
		{
			private ConnectionType _type;

			public SteamId SteamId { get; }

			public ulong? ClientId => UnityConnection?.request.ClientNetworkId;

			public string Name
			{
				get
				{
					//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_0028: 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_0037: Unknown result type (might be due to invalid IL or missing references)
					//IL_003c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0067: Unknown result type (might be due to invalid IL or missing references)
					//IL_006c: Unknown result type (might be due to invalid IL or missing references)
					switch (_type)
					{
					case ConnectionType.Steam:
					{
						SteamId steamId = SteamId;
						object obj;
						if (!((SteamId)(ref steamId)).IsValid)
						{
							obj = "????";
						}
						else
						{
							Friend val = new Friend(SteamId.op_Implicit(SteamId.Value));
							obj = ((Friend)(ref val)).Name;
						}
						return (string?)obj + $"({ClientId})";
					}
					case ConnectionType.IP:
					{
						NetworkEndPoint endPoint = EndPoint;
						return $"{((NetworkEndPoint)(ref endPoint)).Address}({ClientId})";
					}
					default:
						throw new ArgumentOutOfRangeException();
					}
				}
			}

			public ushort QueuePosition
			{
				get
				{
					if (_connectingClient == this)
					{
						return 1;
					}
					int num = Array.IndexOf(ConnectionQueue.ToArray(), this);
					return (ushort)((num >= 0) ? ((uint)(num + 1)) : 0u);
				}
			}

			public NetworkEndPoint EndPoint { get; }

			public (ConnectionApprovalRequest request, ConnectionApprovalResponse response)? UnityConnection { get; internal set; }

			public Connection? PreLobbyConnection { get; private set; }

			internal ConnectionQueueEntry(ConnectionApprovalRequest request, ConnectionApprovalResponse response, SteamId identity)
			{
				//IL_000e: 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_0015: Unknown result type (might be due to invalid IL or missing references)
				_type = ConnectionType.Steam;
				SteamId = identity;
				UnityConnection = (request, response);
			}

			internal ConnectionQueueEntry(ConnectionApprovalRequest request, ConnectionApprovalResponse response, NetworkEndPoint identity)
			{
				//IL_000e: 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_0015: Unknown result type (might be due to invalid IL or missing references)
				_type = ConnectionType.IP;
				EndPoint = identity;
				UnityConnection = (request, response);
			}

			internal ConnectionQueueEntry(Connection preLobbyConnection, SteamId identity)
			{
				//IL_000e: 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_0015: Unknown result type (might be due to invalid IL or missing references)
				_type = ConnectionType.Steam;
				SteamId = identity;
				PreLobbyConnection = preLobbyConnection;
			}

			internal void DropConnection()
			{
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0041: Unknown result type (might be due to invalid IL or missing references)
				if (UnityConnection.HasValue)
				{
					ForcefullyDisconnectClient(ClientId.Value);
				}
				if (PreLobbyConnection.HasValue)
				{
					Connection value = PreLobbyConnection.Value;
					((Connection)(ref value)).Close(false, 0, "Closing Connection");
					PreLobbyConnection = null;
				}
			}

			internal void RefuseConnection([NotNull] string reason)
			{
				if (UnityConnection.HasValue)
				{
					UnityConnection.Value.response.Approved = false;
					UnityConnection.Value.response.Reason = reason;
					UnityConnection.Value.response.Pending = false;
				}
				else
				{
					DropConnection();
				}
			}

			internal void AcceptConnection()
			{
				if (UnityConnection.HasValue)
				{
					UnityConnection.Value.response.Approved = true;
					UnityConnection.Value.response.Pending = false;
				}
			}

			public override string ToString()
			{
				//IL_001f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Unknown result type (might be due to invalid IL or missing references)
				//IL_003a: 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_0044: Unknown result type (might be due to invalid IL or missing references)
				//IL_005e: Unknown result type (might be due to invalid IL or missing references)
				//IL_008a: Unknown result type (might be due to invalid IL or missing references)
				//IL_008f: Unknown result type (might be due to invalid IL or missing references)
				StringBuilder stringBuilder = new StringBuilder("{Name: ");
				switch (_type)
				{
				case ConnectionType.Steam:
				{
					SteamId steamId = SteamId;
					if (((SteamId)(ref steamId)).IsValid)
					{
						Friend val = new Friend(SteamId.op_Implicit(SteamId.Value));
						stringBuilder.Append(((Friend)(ref val)).Name);
						stringBuilder.Append(", SteamID:").Append(SteamId.Value);
					}
					else
					{
						stringBuilder.Append("-");
					}
					break;
				}
				case ConnectionType.IP:
				{
					StringBuilder stringBuilder2 = stringBuilder.Append(", Endpoint: ");
					NetworkEndPoint endPoint = EndPoint;
					stringBuilder2.Append(((NetworkEndPoint)(ref endPoint)).Address);
					break;
				}
				default:
					throw new ArgumentOutOfRangeException();
				}
				stringBuilder.Append(", ClientId: ").Append(ClientId);
				stringBuilder.Append("}");
				return stringBuilder.ToString();
			}
		}

		public enum ConnectionType
		{
			Steam,
			IP
		}

		private static bool _checkpointsInitialized;

		private static ConnectionCheckpoint _syncAlreadyHeldObjectsCheckpoint;

		private static ConnectionCheckpoint _sendNewPlayerValuesCheckpoint;

		private static ConnectionCheckpoint _syncAllPlayerLevelsCheckpoint;

		private static ConnectionQueueEntry _connectingClient;

		internal static readonly ConcurrentQueue<ConnectionQueueEntry> ConnectionQueue = new ConcurrentQueue<ConnectionQueueEntry>();

		internal static readonly FreeRunningTimer ConnectionTimer = new FreeRunningTimer();

		private static readonly Stopwatch ConnectionStopwatch = new Stopwatch();

		[CanBeNull]
		internal static ConnectionQueueEntry ConnectingClient
		{
			get
			{
				return _connectingClient;
			}
			private set
			{
				_connectingClient = value;
				ConnectionEvents.ResetCheckpoints();
			}
		}

		internal static int QueuedClients => ConnectionQueue.Count + ((ConnectingClient != null) ? 1 : 0);

		internal static void Init()
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Expected O, but got Unknown
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Expected O, but got Unknown
			//IL_020f: 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_0223: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(StartOfRound), "SyncAlreadyHeldObjectsServerRpc", (Type[])null, (Type[])null);
			if (RPCUtils.TryGetRpcID(methodInfo, out var rpcID))
			{
				MethodInfo methodInfo2 = AccessTools.Method(typeof(StartOfRound), $"__rpc_handler_{rpcID}", (Type[])null, (Type[])null);
				MethodInfo methodInfo3 = AccessTools.Method(typeof(JoinQueuePatches), "OnSyncAlreadyHeldObjectsServerRpc", (Type[])null, (Type[])null);
				LobbyControl.Harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(methodInfo3), (HarmonyMethod)null);
			}
			else
			{
				LobbyControl.Log.LogFatal((object)"Could not find RPC id for SyncAlreadyHeldObjectsServerRpc");
			}
			methodInfo = AccessTools.Method(typeof(PlayerControllerB), "SendNewPlayerValuesServerRpc", (Type[])null, (Type[])null);
			if (RPCUtils.TryGetRpcID(methodInfo, out rpcID))
			{
				MethodInfo methodInfo4 = AccessTools.Method(typeof(PlayerControllerB), $"__rpc_handler_{rpcID}", (Type[])null, (Type[])null);
				MethodInfo methodInfo5 = AccessTools.Method(typeof(JoinQueuePatches), "OnSendNewPlayerValuesServerRpc", (Type[])null, (Type[])nu